Fix deadlock when updating tracker pattern last_matched_at
Replace per-row UPDATE inside the detected-tracker loop with a single bulk UPDATE ... WHERE id = ANY(...) after the loop. The old approach locked pattern rows in request-dependent order, causing deadlocks under concurrent ReportDetectedTrackers calls. Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -2023,6 +2023,7 @@ func (s *Service) ReportDetectedTrackers(
|
|||||||
|
|
||||||
inserted := 0
|
inserted := 0
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
var matchedPatternIDs []gid.GID
|
||||||
|
|
||||||
for _, dc := range req.Cookies {
|
for _, dc := range req.Cookies {
|
||||||
if err := s.reportDetectedTracker(
|
if err := s.reportDetectedTracker(
|
||||||
@@ -2040,6 +2041,7 @@ func (s *Service) ReportDetectedTrackers(
|
|||||||
InitiatorURL: dc.InitiatorURL,
|
InitiatorURL: dc.InitiatorURL,
|
||||||
},
|
},
|
||||||
&inserted,
|
&inserted,
|
||||||
|
&matchedPatternIDs,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -2060,6 +2062,7 @@ func (s *Service) ReportDetectedTrackers(
|
|||||||
InitiatorURL: ds.InitiatorURL,
|
InitiatorURL: ds.InitiatorURL,
|
||||||
},
|
},
|
||||||
&inserted,
|
&inserted,
|
||||||
|
&matchedPatternIDs,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -2083,6 +2086,13 @@ func (s *Service) ReportDetectedTrackers(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(matchedPatternIDs) > 0 {
|
||||||
|
var patterns coredata.TrackerPatterns
|
||||||
|
if err := patterns.UpdateLastMatchedAt(ctx, tx, scope, matchedPatternIDs, now); err != nil {
|
||||||
|
return fmt.Errorf("cannot update tracker pattern last_matched_at: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if inserted > 0 {
|
if inserted > 0 {
|
||||||
if err := banner.SetPatternAnalysisRequested(ctx, tx); err != nil {
|
if err := banner.SetPatternAnalysisRequested(ctx, tx); err != nil {
|
||||||
return fmt.Errorf("cannot request pattern analysis: %w", err)
|
return fmt.Errorf("cannot request pattern analysis: %w", err)
|
||||||
@@ -2112,6 +2122,7 @@ func (s *Service) reportDetectedTracker(
|
|||||||
now time.Time,
|
now time.Time,
|
||||||
info detectedTrackerInfo,
|
info detectedTrackerInfo,
|
||||||
inserted *int,
|
inserted *int,
|
||||||
|
matchedPatternIDs *[]gid.GID,
|
||||||
) error {
|
) error {
|
||||||
var matchedPattern coredata.TrackerPattern
|
var matchedPattern coredata.TrackerPattern
|
||||||
err := matchedPattern.FindMatchingPattern(ctx, tx, scope, banner.ID, info.TrackerType, info.Identifier)
|
err := matchedPattern.FindMatchingPattern(ctx, tx, scope, banner.ID, info.TrackerType, info.Identifier)
|
||||||
@@ -2126,11 +2137,7 @@ func (s *Service) reportDetectedTracker(
|
|||||||
var patternID *gid.GID
|
var patternID *gid.GID
|
||||||
if err == nil {
|
if err == nil {
|
||||||
patternID = &matchedPattern.ID
|
patternID = &matchedPattern.ID
|
||||||
matchedPattern.LastMatchedAt = &now
|
*matchedPatternIDs = append(*matchedPatternIDs, matchedPattern.ID)
|
||||||
matchedPattern.UpdatedAt = now
|
|
||||||
if updateErr := matchedPattern.Update(ctx, tx, scope); updateErr != nil {
|
|
||||||
return fmt.Errorf("cannot update tracker pattern last_matched_at: %w", updateErr)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
newPattern := &coredata.TrackerPattern{
|
newPattern := &coredata.TrackerPattern{
|
||||||
ID: gid.New(scope.GetTenantID(), coredata.TrackerPatternEntityType),
|
ID: gid.New(scope.GetTenantID(), coredata.TrackerPatternEntityType),
|
||||||
|
|||||||
@@ -801,6 +801,44 @@ WHERE
|
|||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tps *TrackerPatterns) UpdateLastMatchedAt(
|
||||||
|
ctx context.Context,
|
||||||
|
tx pg.Tx,
|
||||||
|
scope Scoper,
|
||||||
|
patternIDs []gid.GID,
|
||||||
|
matchedAt time.Time,
|
||||||
|
) error {
|
||||||
|
if len(patternIDs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
q := `
|
||||||
|
UPDATE tracker_patterns
|
||||||
|
SET
|
||||||
|
last_matched_at = @matched_at,
|
||||||
|
updated_at = @updated_at
|
||||||
|
WHERE
|
||||||
|
%s
|
||||||
|
AND id = ANY(@pattern_ids)
|
||||||
|
`
|
||||||
|
|
||||||
|
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||||
|
|
||||||
|
args := pgx.StrictNamedArgs{
|
||||||
|
"pattern_ids": patternIDs,
|
||||||
|
"matched_at": matchedAt,
|
||||||
|
"updated_at": matchedAt,
|
||||||
|
}
|
||||||
|
maps.Copy(args, scope.SQLArguments())
|
||||||
|
|
||||||
|
_, err := tx.Exec(ctx, q, args)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot update last_matched_at for tracker patterns: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (tps *TrackerPatterns) MoveToCategoryByCookieCategoryID(
|
func (tps *TrackerPatterns) MoveToCategoryByCookieCategoryID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
tx pg.Tx,
|
tx pg.Tx,
|
||||||
|
|||||||
Reference in New Issue
Block a user