Skip to content

feat: route GET/HEAD requests to an optional read replica - #46

Merged
lesnik512 merged 1 commit into
mainfrom
feat/read-replica-session
Sep 27, 2026
Merged

lesnik512 merged 1 commit into
mainfrom
feat/read-replica-session

Conversation

@lesnik512

Copy link
Copy Markdown
Member

Closes #45.

Port of modern-python/fastapi-sqlalchemy-template#71.

What

  • New DB_REPLICA_DSN setting (default empty). When set, GET/HEAD requests use a replica engine; every other method, and any resolution without a request, uses the primary. When unset, behaviour is unchanged and no second pool is created.
  • app/ioc.py: database_engine (primary), database_replica_engine (AsyncEngine | None), and a request-scoped dynamic_engine chosen by choose_sa_engine. The session gets dynamic_engine via explicit kwargs.
  • Tests override dynamic_engine with the rolled-back connection, so reads and writes still share one transaction.
  • tests/test_db_routing.py covers method routing, no-request fallback, no-replica fallback, and building the replica engine from the DSN.

Design notes

  • Session wired to dynamic_engine explicitly; both base engines are bound_type=None so modern-di does not raise a duplicate-type error.
  • The replica provider returns None rather than aliasing the primary provider, so routing is testable by overriding each engine independently.
  • app/resources/*.py is exempted from ruff's TC rules: modern-di evaluates creator annotations at runtime, and moving import litestar under TYPE_CHECKING breaks resolution.
  • Tests build requests with RequestFactory().get("/") and set the scope method, since RequestFactory has no HEAD helper and ty rejects a raw dict scope.

Caveats

  • Replica lag: a client that writes and immediately reads may see stale data.
  • GET handlers must not write; they would hit the replica.

@lesnik512
lesnik512 merged commit e2cc25e into main Sep 27, 2026
2 checks passed
@lesnik512
lesnik512 deleted the feat/read-replica-session branch September 27, 2026 20:18
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.

Add dynamic orm session (read-write)

1 participant