From b6d0b64224bd20aea450b98cc9e4051db60ea70d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89mile=20R=C3=A9?= Date: Fri, 29 May 2026 17:42:33 +0200 Subject: [PATCH] Skip mapping when tracker pattern deleted concurrently MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tracker-mapping worker runs its LLM and web-search phases between short transactions and holds no row lock across them. The pattern-analysis worker can merge a pattern into a glob and delete it in that window, so the final UpdateMapping then fails with ErrResourceNotFound and the task errors out spuriously. A vanished pattern has nothing left to map, so treat the concurrent delete as a no-op: log it and return nil instead of failing. Signed-off-by: Émile Ré --- pkg/cookiebanner/tracker_mapping_worker.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pkg/cookiebanner/tracker_mapping_worker.go b/pkg/cookiebanner/tracker_mapping_worker.go index 11df9292e..e477355b4 100644 --- a/pkg/cookiebanner/tracker_mapping_worker.go +++ b/pkg/cookiebanner/tracker_mapping_worker.go @@ -236,6 +236,22 @@ func (h *trackerMappingHandler) Process(ctx context.Context, tp coredata.Tracker } if err := tp.UpdateMapping(ctx, tx, scope); err != nil { + // The pattern can be merged into a glob and deleted by + // the pattern-analysis worker while this worker holds no + // row lock (the LLM/web-search phases run between short + // transactions). A vanished pattern has nothing left to + // map, so treat the concurrent delete as a no-op instead + // of failing the task. + if errors.Is(err, coredata.ErrResourceNotFound) { + h.logger.InfoCtx( + ctx, + "tracker pattern deleted before mapping could be persisted, skipping", + log.String("tracker_pattern_id", tp.ID.String()), + ) + + return nil + } + return fmt.Errorf("cannot update tracker pattern mapping: %w", err) }