{"record":{"id":"2e8931588ca759ce","repo":"multica-ai/multica","slug":"acquire-advisory-lock-4246-w","errorCode":null,"errorMessage":"acquire advisory lock 4246: %w","messagePattern":"acquire advisory lock 4246: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/cmd/backfill_task_usage_hourly/main.go","lineNumber":108,"sourceCode":"\tdefer pool.Close()\n\n\tif err := pool.Ping(ctx); err != nil {\n\t\treturn fmt.Errorf(\"ping database: %w\", err)\n\t}\n\n\t// Serialise against the cron rollup and any other backfill run via\n\t// advisory lock 4246 — the same id the cron entry checks with\n\t// pg_try_advisory_lock. While this backfill holds it, the cron tick\n\t// no-ops instead of racing on task_usage_hourly row locks; a second\n\t// concurrent backfill blocks here until this one finishes. The lock\n\t// is held on a dedicated session connection for the whole run.\n\tlockConn, err := pool.Acquire(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"acquire advisory-lock connection: %w\", err)\n\t}\n\tdefer lockConn.Release()\n\tif _, err := lockConn.Exec(ctx, `SELECT pg_advisory_lock(4246)`); err != nil {\n\t\treturn fmt.Errorf(\"acquire advisory lock 4246: %w\", err)\n\t}\n\tdefer func() {\n\t\t// Unlock on a fresh context so a cancelled ctx (SIGINT) does not\n\t\t// skip the release. Releasing the connection afterwards would end\n\t\t// the session anyway, but an explicit unlock frees it immediately.\n\t\t_, _ = lockConn.Exec(context.Background(), `SELECT pg_advisory_unlock(4246)`)\n\t}()\n\n\tvar minTS, maxTS pgtype.Timestamptz\n\tif err := pool.QueryRow(ctx, `SELECT MIN(created_at), MAX(created_at) FROM task_usage`).Scan(&minTS, &maxTS); err != nil {\n\t\treturn fmt.Errorf(\"scan task_usage time range: %w\", err)\n\t}\n\tif !minTS.Valid {\n\t\tslog.Info(\"task_usage is empty; nothing to backfill\")\n\t\tif *dryRun {\n\t\t\treturn nil\n\t\t}\n\t\treturn stampWatermark(ctx, pool)","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/cmd/backfill_task_usage_hourly/main.go#L90-L126","documentation":"Executing SELECT pg_advisory_lock(4246) on the dedicated session connection failed. Note this is the blocking variant: a second backfill normally WAITS here, not errors. An actual error means the session broke (network drop, server restart, admin terminating the backend), the context was cancelled while queued, or a statement timeout fired while waiting for the lock.","triggerScenarios":"SIGINT cancels ctx while this backfill is queued behind the cron rollup holding 4246; Postgres restarts mid-wait; pg_cancel_backend/pg_terminate_backend from an operator; statement_timeout set in the session.","commonSituations":"Two backfills or a backfill plus cron tick contending on lock 4246 with the second one interrupted while blocked; server failover during the wait.","solutions":["Re-run the backfill — the lock is session-scoped and released when the dead session ends, and slices are idempotent","If it recurs, query pg_locks/pg_stat_activity to see who holds advisory lock 4246 (SELECT pid, grantee... FROM pg_locks WHERE locktype='advisory')","Disable/raise statement_timeout for this session if a DB-level timeout is aborting the wait"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if _, err := lockConn.Exec(ctx, `SELECT pg_advisory_lock(4246)`); err != nil {\n    return fmt.Errorf(\"acquire advisory lock 4246: %w\", err)\n}","preventionTips":["Expect this to BLOCK, not fail, when contended — a failure means the session died","Disable statement_timeout for the locking session","Re-run after server restarts; slices are idempotent"],"tags":["go","postgres","advisory-lock","concurrency"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}