You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Chunk drops deadlock (40P01) with the alert pass's database-state seed; the victim side has no retry #4606
A deadlock (SQLSTATE 40P01) between a chunk drop and a concurrent statement has hit three monitoring stores over 14 days, one each:
2026-09-17 15:56Z and 2026-09-23 15:54Z, two stores: a TimescaleDB policy_retention job on collection_log failed with "deadlock detected. Process … waits for AccessExclusiveLock on relation …" (timescaledb_information.job_errors, one row each). The job retries on its own schedule, so each cost one retention run.
2026-09-28 11:57:34Z, a third store: the deadlock victim was the alert pass's INSERT INTO config.database_state_expected … SELECT … FROM database_states … (AccessShareLock), against a SELECT drop_chunks(…) holding or waiting for AccessExclusiveLock. That cost one alert pass's database-state seed.
Each one is rare and self-heals, but the victim side has no handling, so the failure surfaces as an alert-pass error.
The alert read adapter's database-state sequence has no 40P01 handling. That's the seed, heal and prune of config.database_state_expected in GetDatabaseStatesCoreAsync, Darling/PerformanceMonitor.Darling.Service/DarlingAlertReadAdapter.cs ~1446–1454 and ~1622–1676, each statement autocommit. Its ExecuteWithOneRetryAsync seam (~287–364) retries client-side command timeouts only; a PostgresException, 40P01 included, is excluded on purpose.
Neither side sets lock_timeout.
It's unconfirmed which code path created a TimescaleDB retention policy on collection_log on the two stores whose job failed. The product purges collection_log itself with drop_chunks.
Fix
Give the alert adapter's database-state sequence one retry on 40P01, in the same shape as the purge's retry. A deadlock victim's statement is rolled back whole, and the seed is ON CONFLICT DO NOTHING, so a retry is safe. Check the heal/prune statements are idempotent the same way, and log the retry once.
Confirm where the collection_log retention job comes from: grep RetentionPolicies, the historical rungs, and Lite's parity. If the product creates it, say so beside the purge. If not, note that an out-of-band policy on collection_log duplicates the product's own purge.
Pins:
the classifier/seam treats 40P01 as a one-shot retry;
a simulated deadlock (a fake PostgresException with 40P01, as DarlingRetentionTests' DropChunksRetry_* do) retries once and succeeds, and twice gives up and surfaces;
Fixed in #4612 (605249b). The alert pass's database-state maintenance (seed, heal, prune, clear-recovered) retries once when PostgreSQL picks it as a deadlock victim (40P01), the way the daily purge retries its chunk drops; other errors are not retried. The unexplained retention policy on collection_log reported alongside this is not addressed here.
Activity
Alert pass: the database-state maintenance retries once on a deadlock (…
erikdarlingdata commentedon Sep 28, 2026
Claude posting for Erik Darling.
Fixed in #4612 (605249b). The alert pass's database-state maintenance (seed, heal, prune, clear-recovered) retries once when PostgreSQL picks it as a deadlock victim (40P01), the way the daily purge retries its chunk drops; other errors are not retried. The unexplained retention policy on collection_log reported alongside this is not addressed here.