From 31dc8913acee0b0788cdda61be4c2a10f209f11d Mon Sep 17 00:00:00 2001 From: shaw Date: Tue, 16 Jun 2026 11:57:32 +0800 Subject: [PATCH] chore(outbox-cleanup): add 10s grace to defend against id-vs-commit race PG sequences advance outside transactions, so a slow committer can hold an id that gets surpassed by the watermark before its commit becomes visible. Without the grace period, cleanup would delete such rows before the snapshot poller ever sees them. 10s is a comfortable upper bound on realistic enqueueSchedulerOutbox commit latency. --- backend/internal/repository/scheduler_outbox_repo.go | 5 +++++ backend/internal/repository/scheduler_outbox_repo_test.go | 1 + 2 files changed, 6 insertions(+) diff --git a/backend/internal/repository/scheduler_outbox_repo.go b/backend/internal/repository/scheduler_outbox_repo.go index cea5d451f6..59772fbb5a 100644 --- a/backend/internal/repository/scheduler_outbox_repo.go +++ b/backend/internal/repository/scheduler_outbox_repo.go @@ -108,11 +108,16 @@ func (r *schedulerOutboxRepository) DeleteConsumedUpTo(ctx context.Context, wate if limit <= 0 { limit = schedulerOutboxDefaultCleanSize } + // created_at < NOW() - INTERVAL '10 seconds' 防御 PG 序列号在事务内提前分配但 + // 提交延迟的竞争:若某 Tx 在 watermark 推进前持有 id=N(未提交),watermark + // 跨过 N 后该 Tx 才提交,此时 row N 已经"低于 watermark"但从未被 poll;10s + // 宽限期让此类慢事务有机会提交后被消费,再被 cleanup 删除。 result, err := r.db.ExecContext(ctx, ` WITH doomed AS ( SELECT id FROM scheduler_outbox WHERE id <= $1 + AND created_at < NOW() - INTERVAL '10 seconds' ORDER BY id ASC LIMIT $2 ) diff --git a/backend/internal/repository/scheduler_outbox_repo_test.go b/backend/internal/repository/scheduler_outbox_repo_test.go index ea91f6c73e..6b4a1af9e9 100644 --- a/backend/internal/repository/scheduler_outbox_repo_test.go +++ b/backend/internal/repository/scheduler_outbox_repo_test.go @@ -20,6 +20,7 @@ func TestSchedulerOutboxRepositoryDeleteConsumedUpToUsesBoundedCTE(t *testing.T) SELECT id FROM scheduler_outbox WHERE id <= $1 + AND created_at < NOW() - INTERVAL '10 seconds' ORDER BY id ASC LIMIT $2 )