Skip to content

perf: run the single-statement reads at AUTOCOMMIT - #64

Merged
lesnik512 merged 2 commits into
mainfrom
perf/autocommit-single-reads
Oct 17, 2026
Merged

lesnik512 merged 2 commits into
mainfrom
perf/autocommit-single-reads

Conversation

@lesnik512

Copy link
Copy Markdown
Member

Follow-up to #63. Login, GET /auth/me/, GET /chats/ and GET /chats/{id}/ each run one use case that sends a single SELECT. They now use Database.autocommit_transaction, as the revocation check already does, so the asyncpg adapter sends that SELECT without a BEGIN or a COMMIT. That saves 2 round trips per request.

Round trips

Measured against a real engine on this branch with a scratch test (not committed). It counted every statement SQLAlchemy sent plus every asyncpg.Connection.execute call, which is how the adapter sends BEGIN and COMMIT. Each request ran once to warm the statement cache before it was measured. Authenticated rows include the revocation check, which is already one round trip after #63.

Endpoint before after sent after
POST /auth/login/ 3 1 SELECT
GET /auth/me/ 4 2 SELECT, SELECT
GET /chats/ 4 2 SELECT, SELECT
GET /chats/{id}/ 4 2 SELECT, SELECT
GET /chats/{id}/messages/ 5 5 unchanged

The message list stays in a normal transaction. It checks membership and then lists the page, and the two reads should see the same snapshot. Statement counts do not change, so tests/api/test_statement_counts.py is untouched.

Changes

  • ioc.UseCases: the four providers get kwargs={"transaction": Database.autocommit_transaction}. Each query is still inside its Transaction block, so the recovery from ADR 0010 still applies.
  • tests/use_cases/test_check_token_revoked.py is now test_autocommit_reads.py. It runs each of the five autocommit use cases against a real engine and checks that asyncpg reports no open transaction while the query runs. The first commit adds the four new cases, and they fail on main.
  • tests/use_cases/test_connection_loss.py: the four use cases move out of the lost-connection-in-session tests and stay in the pooled ones. The in-session fixture leaves the request session holding a connection before the use case starts, and SQLAlchemy then ignores the isolation option with SAWarning: Connection is already established for the given bind; execution_options ignored, which filterwarnings = error turns into a failure. Production cannot reach that state for these use cases. Each endpoint runs one use case on a fresh request session, and Transaction.__aexit__ closes the session before postgres_retry tries again. perf: cut avoidable SQL round trips from every endpoint #63 made the same call for the revocation check. The in-session tests still cover the message list, message send and mark-read.
  • AGENTS.md lists which use cases take the autocommit transaction and why multi-statement reads do not.

Testing

just test: 154 passed, coverage 100%. just lint is clean.

@lesnik512
lesnik512 merged commit d77c6ea into main Oct 17, 2026
4 checks passed
@lesnik512
lesnik512 deleted the perf/autocommit-single-reads branch October 17, 2026 11:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant