{"record":{"id":"da023efe437a5938","repo":"multica-ai/multica","slug":"acquire-advisory-lock-connection-w","errorCode":null,"errorMessage":"acquire advisory-lock connection: %w","messagePattern":"acquire advisory-lock connection: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/cmd/backfill_codex_usage_cache/main.go","lineNumber":115,"sourceCode":"\t}\n\n\trows, total, err := loadDryRunSummary(ctx, pool, cfg)\n\tif err != nil {\n\t\treturn err\n\t}\n\tlogSummary(cfg, rows, total)\n\tif total.Rows == 0 {\n\t\tslog.Info(\"no eligible Codex task_usage rows found\")\n\t\treturn nil\n\t}\n\tif !cfg.execute {\n\t\tslog.Info(\"dry-run complete; review the summary, then re-run with --execute to apply the backfill\")\n\t\treturn nil\n\t}\n\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($1)`, rollupAdvisoryLockID); err != nil {\n\t\treturn fmt.Errorf(\"acquire advisory lock %d: %w\", rollupAdvisoryLockID, err)\n\t}\n\tdefer func() {\n\t\t_, _ = lockConn.Exec(context.Background(), `SELECT pg_advisory_unlock($1)`, rollupAdvisoryLockID)\n\t}()\n\n\tupdateStartedAt, err := databaseClock(ctx, pool)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tupdatedRows, removedTokens, err := executeBackfill(ctx, pool, cfg)\n\tif err != nil {\n\t\treturn err\n\t}","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/cmd/backfill_codex_usage_cache/main.go#L97-L133","documentation":"Returned when pool.Acquire fails while the backfill tries to dedicate one pooled connection to hold a pg advisory lock for the update phase. In practice this fires only after --execute is set and eligible rows exist, and almost always means ctx was cancelled (SIGINT/SIGTERM via signal.NotifyContext) or the pool hit its max size / was closed — not a database protocol error.","triggerScenarios":"Sending SIGINT/SIGTERM to a running --execute backfill just as it moves from the dry-run summary into the locked update phase; pool exhaustion because max_conns is tiny and other sessions hold them; pool already closed.","commonSituations":"Operator Ctrl-C's the tool during a long run; a supervisor with a short timeout kills it at phase transition; DATABASE_URL embeds pool limiting parameters that leave fewer than 1 free connection.","solutions":["If you interrupted the tool intentionally, just re-run with --execute — the advisory lock design makes re-running safe.","Remove pool-limiting params from the DSN or raise max_conns so one connection is free.","Run the tool under a longer timeout / with nohup so phase transitions are not killed mid-acquire."],"exampleFix":"# before\n./backfill_codex_usage_cache --cutoff ... --execute &  # killed by 30s supervisor timeout\n# acquire advisory-lock connection: context canceled\n\n# after\nnohup ./backfill_codex_usage_cache --cutoff 2026-01-01T00:00:00Z --execute >backfill.log 2>&1 &","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run the --execute phase under nohup/tmux with generous timeouts so phase transitions are not killed.","Keep at least one spare pool connection (avoid tiny max_conns in the DSN).","Know that a re-run after cancellation is safe — the tool's eligibility predicate self-excludes corrected rows."],"tags":["database","backfill","advisory-lock","context-cancellation","pool"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}