Skip to content

Add additive staleness to follower reads; fix SQLAlchemy session helper - #2

Merged
felipeg48 merged 1 commit into
mainfrom
fix/7-follower-reads
Oct 28, 2026
Merged

felipeg48 merged 1 commit into
mainfrom
fix/7-follower-reads

Conversation

@felipeg48

Copy link
Copy Markdown
Contributor

PR: Follower-read staleness controls + fix SQLAlchemy session helper

Repo: cockroachlabs/cockroachdb-python-library
Branch: fix/7-follower-reads → main
Suggested bump after merge: patch on cockroachdb, cockroachdb-core,
cockroachdb-sqlalchemy (additive feature + bug fix)

Summary

Ports the follower-read contract from the Spring Boot starter and fixes a
SQLAlchemy session helper that raised AttributeError at runtime.

The bug (confirmed)

cockroachdb.sqla.session.follower_read() called FollowerReadContext.set(True) /
reset(token) — methods that do not exist (the class exposes is_active,
current_staleness, scoped) — and passed a bool into a str | None contextvar.
Any caller on that path got an AttributeError. Live in the published
cockroachdb-continuum 0.1.1. Now uses the real FollowerReadContext.scoped()
contextmanager.

What changed

  • hours_ago/minutes_ago/seconds_ago keyword-only params added to the
    follower_read() decorator, FollowerReadContext.scoped(), and the SQLAlchemy
    session helper. They add up and compose to AS OF SYSTEM TIME '-Ns'; nothing set
    keeps follower_read_timestamp().
  • New cockroachdb.staleness.build_staleness() — single source of truth for
    composition + validation; exported from cockroachdb. Reused by all three entry
    points so the rule (negative → ValueError) lives in one place.
  • Helper lives in the base cockroachdb package (not core): core depends on
    base, so a base-only install can still import @follower_read without an
    ImportError.

Breaking vs additive

Fully additive. New params are keyword-only with default 0; staleness retained
with the same precedence when no parts are set. All pre-existing tests unchanged and
green.

Testing (verified locally)

  • Changed-path tests (test_follower_read, test_sqla_session, test_decorators,
    test_template) → 86 passed.
  • Full suite under Python 3.13 against a local cockroachdb/cockroach:v26.3.3 node
    → 543 passed, 0 failed.
  • uv run --package cockroachdb-sqlalchemy pytest tests/test_sqla_session.py → 19 passed.

Why the bug shipped: the old TestFollowerRead cases @patched
FollowerReadContext and asserted .set(True)/.reset(token) — they encoded the
non-existent API and passed only because the mock faked it. Replaced with 6 tests
against the real FollowerReadContext (no live DB): staleness activated + reset,
additive composition, negative → ValueError before any session opens, result
passthrough, and context reset + session.close() on exception.

Environment note for CI

The ai extras depend on torch, which has no wheel for CPython 3.15. Run the
suite on Python ≤ 3.14 (3.13 recommended); on 3.15 the ai/cdc/django
collection fails to import because the sync aborts on torch. Not a code issue.

Known limitation (not fixed here)

MetricsCollector.record_follower_read() has zero call sites library-wide —
follower-read metrics are never recorded. Wiring it needs the SQLAlchemy event /
psycopg execution layer; tracked separately.

- hours_ago/minutes_ago/seconds_ago on follower_read(), FollowerReadContext.scoped(), sqla session helper
- build_staleness() single source of truth; ValueError on negative
- Fix sqla session follower_read() runtime AttributeError (called non-existent FollowerReadContext.set/reset)
- Add CHANGELOG and update README follower-reads section
@felipeg48
felipeg48 force-pushed the fix/7-follower-reads branch from 1834fe4 to def1d33 Compare October 28, 2026 12:59
@felipeg48
felipeg48 merged commit 022ed8c into main Oct 28, 2026
3 checks passed
@felipeg48
felipeg48 deleted the fix/7-follower-reads branch October 28, 2026 13:01
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