fix(#3071): align Sqlite DLQ expiration column with the shared 'expires' name#3079
Merged
Conversation
…es' name The Sqlite DeadLettersTable named the conditional expiration column 'keep_until' (DatabaseConstants.KeepUntil) while every other RDBMS backend (Postgres, SqlServer, MySql, Oracle) names it 'expires' (DatabaseConstants.Expires). The shared DLQ insert path in DatabasePersistence.WriteDeadLetter and the cleanup query in DeleteExpiredDeadLetterMessagesOperation both reference 'expires', so Sqlite hosts with DeadLetterQueueExpirationEnabled = true hit 'SqliteException: no such column: expires' both on the periodic cleanup job and on the next DLQ insert. Renaming the column to 'expires' (the constant the shared SQL uses) closes the gap. The reporter notes the bug shows up on a fresh database too — exactly what the test exercises. Regression test mirrors the bug report verbatim: PersistMessagesWithSqlite + DeadLetterQueueExpirationEnabled=true + AddResourceSetupOnStartup, then asserts the dead_letters table has an 'expires' column and not the legacy 'keep_until'. A second case exercises the off-default to lock in that 'expires' is gated correctly. All 142 SqliteTests green (1 pre-existing skip). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced Jun 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #3071.
Diagnosis
The Sqlite
DeadLettersTablenamed the conditional expiration columnkeep_until(DatabaseConstants.KeepUntil) while every other RDBMS backend — Postgres, SqlServer, MySql, Oracle — names itexpires(DatabaseConstants.Expires):The shared DLQ insert path (
Wolverine.RDBMS.DatabasePersistence.WriteDeadLetter) and the cleanup query (Wolverine.RDBMS.Durability.DeleteExpiredDeadLetterMessagesOperation) both targetDatabaseConstants.Expires:So a Sqlite host with
DeadLetterQueueExpirationEnabled = trueprovisions a column the shared SQL never writes to and then hitsSqliteException: no such column: expireson the periodic cleanup job (and on the next DLQ insert). The reporter calls out that this happens on a fresh database too — confirmed by the regression test.The fix
Rename the column to
expiresso it matches the constant the shared SQL uses. One line inWolverine.Sqlite/Schema/DeadLettersTable.cs. Aligns Sqlite with every other backend.Regression coverage
SqliteTests/Bug_3071_sqlite_dlq_expiration_creates_expires_column.cs— mirrors the bug report verbatim:dlq_table_has_expires_column_when_expiration_is_enabled— boots a host withPersistMessagesWithSqlite + DeadLetterQueueExpirationEnabled = true + AddResourceSetupOnStartup, then asserts thewolverine_dead_letterstable carriesexpiresand not the legacykeep_until. Fails on pre-fix code with the column-name mismatch.dlq_table_has_no_expires_column_when_expiration_is_disabled— regression guard the other way: with expiration off, neither column appears. Locks in the gating so a careless future refactor can't reintroduce the bug from the other side.Reflects column names via
PRAGMA table_infodirectly rather than going through Weasel'sFetchExistingAsyncso the assertion shape is independent of any future Weasel column-name normalization choice.All 142
SqliteTestsgreen (1 pre-existing skip).Why no migration
The bug never produced a working install — the cleanup job throws on every pass — so there's no existing fleet of Sqlite databases out there with a populated
keep_untilcolumn to migrate. Anyone who flipped the flag on either ran into the exception immediately or never enabled the feature. Renaming the column is the right end-state and any in-flight database that did happen to provision the wrong-named empty column will simply re-provision the correct one on next resource-setup pass.🤖 Generated with Claude Code