Skip to content

chore(deps): raise the sqlalchemy floor on 3.14; drop the GIL workaround - #189

Merged
lesnik512 merged 1 commit into
mainfrom
deps/sqlalchemy-freethread-floor
Sep 20, 2026
Merged

lesnik512 merged 1 commit into
mainfrom
deps/sqlalchemy-freethread-floor

Conversation

@lesnik512

Copy link
Copy Markdown
Member

Closes #160.

Why now

#160 waits on SQLAlchemy's cyextensions declaring Py_MOD_GIL_NOT_USED. They do
as of 2.0.54. Measured on CPython 3.14.7t with the compiled extensions
genuinely loaded (has_compiled_ext() == True, collections.cpython-314t-*.so),
no env var set:

sqlalchemy compiled ext GIL after import
2.0.52 (the version in #160) yes enabled
2.0.53 yes enabled
2.0.54 yes disabled

So DISABLE_SQLALCHEMY_CEXT_RUNTIME=1 now buys a slower pure-Python fallback and
nothing else.

What

  • Floor: sqlalchemy[asyncio]>=2.0.54; python_version >= '3.14'. The existing
    marked floor is split so ==3.13 keeps 2.0.31 and below 3.13 keeps 2.0.
  • CI: the env: block goes from the freethreaded job. The job already
    asserts sys._is_gil_enabled() is false, so the floor is now self-gating:
    a regression turns that step red instead of being masked by the workaround.
  • Docs: the admonition in introduction/installation.md kept its second half,
    which is still true (a foreign-broker client like aiokafka still re-enables
    the GIL), and lost the SQLAlchemy instruction.
  • ADR-0002 recorded the workaround as load-bearing. Amended rather than left
    standing, since docs/agents/domain.md tells agents to read ADRs as current
    truth about the area they are working in. The decision itself is unchanged;
    only its bounding constraint moved.

The cost, stated plainly

There is no environment marker for a free-threaded build, so python_version >= '3.14' is the narrowest expressible constraint and ordinary 3.14 users inherit a
2.0.54 floor for a reason that only affects 3.14t. That is the trade for the docs
being able to state the guarantee without a conditional the reader has to
evaluate. Option 2 in the alternative was to keep the floor and rewrite the note
as "only needed below 2.0.54"; this is option 1.

Verified

  • The freethreaded job's exact assertion on 3.14t with no env var: passes,
    GIL disabled with sqlalchemy 2.0.54 | compiled ext: True.
  • Full suite on 3.14t without the workaround: 517 passed, 107 skipped.
  • The lowest leg added in ci: resolve the declared dependency floors on every PR #188 resolves the new floor and passes:
    3.13 to sqlalchemy 2.0.31, 3.14 to 2.0.54, both 517 passed, 107 skipped.
    (The 107 are the Postgres tests, which skip locally and run in CI.)
  • just lint-ci and just docs-build clean.

SQLAlchemy 2.0.54 declares `Py_MOD_GIL_NOT_USED` on its cyextensions, so
importing it no longer re-enables the GIL process-wide on a free-threaded
interpreter. `DISABLE_SQLALCHEMY_CEXT_RUNTIME=1` was buying a slower
pure-Python fallback for nothing.

The floor moves to 2.0.54 on 3.14+ so the docs can state the guarantee
without a conditional. There is no marker for a free-threaded build, so
ordinary 3.14 carries a floor it does not need; 3.13 and below are split
off and unaffected.

Closes #160
@github-actions

Copy link
Copy Markdown

Benchmark gate

✅ gate passed

scenario msg/s delete/msg WALrec/msg WALB/msg fpi upd del dead_tup
consumer/w1/b10 953 1.000 6.79 917 242 5000 5000 10000
consumer/w1/b100 951 1.000 6.83 920 243 5000 5000 10000
consumer/w2/b10 1100 1.000 6.80 961 242 5000 5000 10000
consumer/w2/b100 1295 1.000 6.78 992 263 5000 5000 10000
consumer/w4/b10 974 1.000 6.74 949 243 5000 5000 10000
consumer/w4/b100 1496 1.000 6.86 1032 243 5000 5000 10000
consumer/w1/b100/tfbs100 4967 0.010 6.07 1116 243 5000 5000 10000
producer/w1/b100 2082 0.000 3.04 584 0 0 0 0

Gated (fails the build): delete_calls + tuple counters (upd/del/ins) + the producer's insert_calls, exact; select_calls within +2; wal_records within a 10% band. msg/s, WAL bytes and total calls are informational (timing/FPI noise).

@lesnik512
lesnik512 merged commit 8041da3 into main Sep 20, 2026
12 checks passed
@lesnik512
lesnik512 deleted the deps/sqlalchemy-freethread-floor branch September 20, 2026 14:12
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.

Drop DISABLE_SQLALCHEMY_CEXT_RUNTIME=1 once SQLAlchemy's cyextensions declare free-thread safety

1 participant