-
fix(cache): stringify ids at the SQL bind layer and stop sliding-TTL … (#4182)
发布于
2026-07-22 11:51:20 +00:00 …deadlocks
Two production failures on the Postgres cache backend, both in
SqlCacheAdapter:-
A caller holding user.id as uuid.UUID made the asyncpg dialect bind
the parameter as $1::UUID, so Postgres parsedtext = uuidand raised
42883 ("operator does not exist") instead of coercing; sqlite rejects
such binds outright. Key columns
(user_id/session_id/qa_id/entry_id/log_key/key) now use a StringKey
TypeDecorator that coerces stringable ids to str in the bind processor,
covering every read, write, and IN-list in one place. Client-side only:
the emitted DDL is still plain TEXT (verified identical), so existing
tables keep working with no migration. -
Session writes end with the sliding-TTL UPDATE over all of the
session's rows while already holding row locks taken earlier in the
transaction, so concurrent same-session writers acquired row locks in
opposite orders and deadlocked (40P01) faster than the 3-attempt retry
could absorb. Write transactions now take a transaction-scoped
pg_advisory_xact_lock keyed by (table, user, session) up front, so
same-session writers queue instead. No-op on SQLite.
Verified on Postgres 17: uuid.UUID ids round-trip identically to their
string form, a table created by the previous code (old DDL + legacy
rows) is read and extended seamlessly, and an 8-worker concurrent-update
hammer that previously produced 579 server-side deadlocks (189 surfaced
as CacheConnectionError) now produces 0.Description
Acceptance Criteria
Type of Change
- Bug fix (non-breaking change that fixes an issue)
- New feature (non-breaking change that adds functionality)
- Code refactoring
- Other (please specify):
Screenshots
Pre-submission Checklist
- I have tested my changes thoroughly before submitting this PR
(SeeCONTRIBUTING.md) - This PR contains minimal changes necessary to address the
issue/feature - My code follows the project's coding standards and style
guidelines - I have added tests that prove my fix is effective or that my
feature works - I have added necessary documentation (if applicable)
- All new and existing tests pass
- I have searched existing PRs to ensure this change hasn't been
submitted already - I have linked any relevant issues in the description
- My commits have clear and descriptive messages
DCO Affirmation
I affirm that all code in every commit of this pull request conforms to
the terms of the Topoteretes Developer Certificate of Origin.下载附件
-