feat: free-threading (nogil) support#108
Merged
Merged
Conversation
Full-lane design for certifying httpware under free-threaded CPython (PEP 703): verify-first sequencing, free-threaded CI on 3.14t (full suite + all extras; 3.13t deferred on the msgspec cp313t wheel gap), parallel stress tests for the Lock-based resilience components + the shared httpx2 pool, a committed contention benchmark, and the Free Threading classifier added last. Backed by empirical findings: httpx2 2.5.0 passes a 32-thread shared-pool stress run under nogil, and the extras wheel matrix (pydantic/msgspec/otel) is verified per interpreter. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…hability of guard race arm
…hreading baseline Adds benchmarks/contention.py, measuring shared-RetryBudget throughput under real thread parallelism (GIL 3.11 vs free-threaded 3.14t); not a CI gate, characterization only. Records the baseline numbers plus the project's free-threading findings (extras wheel matrix, httpx2 shared-pool boundary, stress-test coverage) in planning/audits/2026-07-18-free-threading-audit.md.
Ruff and ty are unpinned in pyproject and floated forward since Tasks 2-6 landed: isort now orders these files' imports differently, PLR2004 flags the 200 status literal, and ty's stricter override check flags log_message's narrowed signature. Mechanical fixes only (import order, a named status constant, a stdlib-matching signature) -- no behavior change, confirmed by the full suite still passing at 100% coverage.
The boundary paragraph reported the initial exploratory scratch numbers (32 threads, 3x12,800) rather than the committed test (16 threads x 100 = 1,600, single run). Describe the committed regression test accurately and attribute the heavier design-time validation separately. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the Free Threading :: 2 - Beta classifier and promote the nogil work into the living docs: architecture/resilience.md notes the Lock-based components' free-threaded stress verification and the honest ~1.9x contention-benchmark slowdown (correctness, not speed), architecture/testing.md documents the stress marker convention, and architecture/overview.md adds a supported-versions section. Records the 3.13t msgspec-wheel deferral and ships 0.16.0 release notes.
The RetryBudget and event-loop-guard free-threading tests duplicated existing coverage (test_retry_budget_threadsafety.py's two barrier-synced thread tests; test_bulkhead.py::test_cross_loop_acquire_raises_runtimeerror). Delete the two near-duplicate files and instead mark the existing RetryBudget thread-safety tests @pytest.mark.stress, so the free-threading proof set is labelled without redundant tests. Update the audit doc's test list and drop the now-imprecise "four/five" counts from the change summary + release notes (also scoping the release-notes stress claim to the sync + shared components, matching the resilience.md correction). Full suite 783 passing at 100%. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Certifies
httpwareunder free-threaded CPython (PEP 703), backed by evidence rather than a bare classifier. Verify-first: the public claim (Free Threading :: 2 - Betaclassifier) lands last, after the tests, CI, and benchmark prove it.Full rationale and design:
planning/changes/2026-07-18.01-nogil-free-threading-support.md.What's here
pytest-freethreadedCI job on3.14t(full suite + all extras from prebuilt wheels), asserting the GIL is disabled before the run. Regular GIL matrix (3.11–3.14) unchanged.pytest.mark.stress) for the thread-shared components — syncBulkhead,CircuitBreaker, and the sharedRetryBudget— plus anhttpx2shared-pool boundary test. All pass on 3.14t with the GIL disabled. The asyncAsyncBulkhead/AsyncCircuitBreakerare single-event-loop bound (cross-loop use is rejected by the guard, deterministically tested) and not thread-parallel-stressed by design.benchmarks/contention.py) + recorded baseline. Honest finding: free-threading is ~1.9× slower for the single-shared-lockRetryBudgetworkload — lock contention dominates. This is a correctness certification, not a speedup.Free Threading :: 2 - Betaclassifier andarchitecture/promotion.Scoped out
3.13tis deferred (planning/deferred.md) — msgspec ships no cp313t free-threaded wheel, so 3.13t can't run the extras from wheels.Verification
just lint-cigreen; 783 tests at 100% coverage; all fivestress-marked tests confirmed passing on real3.14twithsys._is_gil_enabled()False.🤖 Generated with Claude Code