πŸš€ release: 2.0.8 wheels (5 platforms incl. free-threaded) + README/CHANGELOG refresh

swadhinbiswas committed 2 months ago
0598cf5
1 parent 8f63e8a
commit 0598cf5
2 files changed
+19 -1
Showing 2 changed files+19-1
β–ΌCHANGELOG.md
+9-0
7
7
8
8
## [2.0.8] - 2026-08-06
9
9
10
+### Added (2026-08-07)
11
+- **Native async DB awaits** β€” `app.db.query_async(sql, params)` / `app.db.execute_async(...)`: awaitable DB ops on the DB's own tokio runtime, GIL released, loop never blocked. **53Γ— faster than the blocking path on slow queries** (320 vs 6 RPS, ADR-093)
12
+- **Multi-worker prefork verified** β€” `justapi serve --workers N --scale`: 4 workers = 1.88Γ— throughput (99.7k RPS), auto-scale respawns (benchmarked 2026-08-07)
13
+- **Type-checked DX** β€” `py.typed` marker + mypy-clean `.pyi` stubs (routes, `app.db`, `native_async`, `sse_native` all typed)
14
+- **Scaffold demos differentiators** β€” `justapi create` generates a CRUD app exercising `query_async`, `@native_async`, and Rust-native SSE
15
+- **Rust-native SSE streaming** β€” `app.sse_native(path, count, interval_ms)`: events generated entirely in Rust, zero Python per event (ADR-088)
16
+- **`@native_async` decorator** β€” marks async handlers for the fastest dispatch; true parallel dispatch on free-threaded CPython (ADR-089)
17
+- **Callback-driven async resolution** β€” `_DoneNotifier` fires on coroutine completion; no blocking wait, no thread hop (ADR-086)
18
+
10
19
### Security Fixes
11
20
- **CRITICAL:** Fixed global panic hook race condition in `panic.rs` (P0-1)
12
21
- **CRITICAL:** Fixed RwLock poisoning panics in `PerRouteCircuitBreakerMiddleware` (P0-2)
13
22
β–ΌREADME.md
+10-1
92
92
93
93
2. **Agent-native serving.** Beyond REST, JustAPI exposes routes as MCP tools, streams validated structured output per-token, and carries multi-turn session state β€” without external SDKs. See [`ROADMAP.md`](ROADMAP.md) for the full agent roadmap.
94
94
95
+3. **Native async DB awaits.** `await app.db.query_async(sql)` / `execute_async(sql)` run SQL on the DB's own multi-threaded tokio runtime with the GIL released β€” the asyncio loop is never blocked, so slow queries (Postgres, network DBs) do not serialize other requests. Measured **53Γ— faster than the blocking path on slow queries** (320 RPS vs 6 RPS, 2M-row CTE).
96
+
97
+4. **Multi-worker prefork scaling.** `justapi serve --workers N --scale` spawns N worker processes sharing one bound socket. Verified: 4 workers = **1.88Γ— throughput** (99.7k RPS vs 53k), auto-scale respawns under load.
98
+
99
+5. **Type-checked DX.** Ships `py.typed` + complete `.pyi` stubs β€” mypy-clean on user code (routes, `app.db`, `native_async`, `sse_native`). `justapi create` scaffolds a full CRUD project demonstrating every differentiator.
100
+
101
+6. **Free-threaded CPython support.** 3.14t wheels (Py_GIL_DISABLED auto-detected): CPU-bound Python handlers scale with cores (12.4Γ— measured).
102
+
95
103
## Competitors, named honestly
96
104
97
105
JustAPI is not the first Rust-backed Python web framework. The following table compares the closest alternatives on raw throughput (Python handler path, same hardware):
118
126
119
127
- **Native fast path requires a schema.** Routes without a `Schema` registered fall back to the Python handler path (~60k rps). The 724k rps number only applies to routes with `native=True` + `Schema`.
120
128
- **Python handler throughput is GIL-bound.** On CPython, the Python dispatch path is capped at ~100-120k rps on this hardware regardless of framework β€” that is the GIL, not a framework limitation. Free-threaded Python (3.13t/3.14t) removes this ceiling.
121
-- **Agent-native workloads are the differentiator.** The benchmarks that matter most for JustAPI are structured-LLM streaming, MCP tool dispatch, and durable agent sessions β€” not hello-world req/s. These workloads are impossible or awkward in every alternative listed above.
129
+- **Light async handlers are loop-bound.** Async Python handlers that only sleep/echo (~4-12k rps) are capped by the asyncio loop + thread hop β€” Granian's direct loop dispatch is ~44k there (ADR-090/091/092 proved no coroutine-driver or multi-loop approach beats asyncio's stepping). We win on real async workloads (1ms-sleep handlers: 3.9k vs Granian 2.9k RPS) and on anything DB/SSE-heavy via native ops.
130
+- **Native fast path requires a schema.** Routes without a `Schema` registered fall back to the Python handler path (~60k rps). The 724k rps number only applies to routes with `native=True` + `Schema`.
122
131
123
132
## Non-goals & not-yet-built
124
133
125
134