Repository navigation
feat: add transactional inbox ledger - #1
Merged
Merged
Conversation
Inbox(session, table) records processed messages by (scope, message_id) in the caller's transaction, with database-clock cleanup in bounded batches. Tests run against PostgreSQL 17 and cover concurrent claims, rollback, cancellation, commit failure and cleanup.
db-retry 0.9, a dev dependency, requires sqlalchemy>=2.0.20, so the floors job could not install 2.0.0 and that floor was never tested.
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.
Adds
Inbox, a processed-message ledger that writes its marker in the caller's own PostgreSQL transaction.What's in it
make_inbox_table(metadata, table_name="inbox"):scopeandmessage_idas the primary key,processed_atdefaulting to the database'snow(), and an index onprocessed_at. The service owns the Alembic migration.Inbox(session, table): takes anAsyncSessionorAsyncConnectionand registers in modern-di like a REQUEST-scoped repository.claim(scope=, message_id=)runsINSERT ... ON CONFLICT DO NOTHING RETURNINGand returns whether this transaction inserted the marker.cleanup_cutoff(retention=)reads the cutoff from the database clock.delete_expired_batch(cutoff=, limit=)deletes one batch withFOR UPDATE SKIP LOCKED.RuntimeErrorwhen its session has no open transaction. A wrongly wired, uncached session therefore fails loudly instead of writing a marker that never commits.Design decisions
Transactionandpostgres_retryalready work.faststream>=0.7.6.Tests
There are 34 tests against real PostgreSQL. Concurrency cases use separate connections and confirm the lock wait through
pg_stat_activity. They cover:postgres_retryCOMMIT, and a redelivery after a lost ackLocally I ran them on Python 3.14 against PostgreSQL 17 with 100% coverage. The rest of the CI matrix (3.11 to 3.15t, plus the PostgreSQL 14 floors job) hasn't run before this PR.
Not covered