Add true-async-server framework#694
Open
EdmondDantes wants to merge 19 commits into
Open
Conversation
Native PHP HTTP server using TrueAsync coroutine engine with ThreadPool for SO_REUSEPORT multi-worker scaling. Supports HTTP/1.1 and HTTP/2 over TLS via ALPN. Covers baseline, pipelined, json, upload, static, async-db, api-4/16, baseline-h2, static-h2, json-tls test profiles.
- Add docker-compose.yml: postgres + server + validator services on a shared bridge network; validator exits with the test result code - Add test/Dockerfile + test/validate.sh: full HTTP/1.1, HTTP/2, TLS, JSON, upload, static, async-db and TCP-fragmentation tests - Fix entry.php: require PostgreSQL.php inside each per-thread closure so every worker thread has the class in its PHP environment - Fix Dockerfile: switch to slim base image with INI tuning - Add ISSUES.md: documents 4 remaining alpha.3 failures with root causes and suggested server-level fixes
Validator now reports 38/38 in steady state against a locally-built php-src + true-async-server. Documents the remaining minor first-run Content-Type race and the host-PHP extensions required when using the override mount.
Five consecutive validator runs against a locally-built php-true-async report 38/38 with no flakes. Removes the previously-noted intermittent Content-Type race (root cause was an external debug print, not a server-side bug).
…ding parsing
- Remove temporary set_error_handler finalize-race tracer.
- Remove per-request fopen('/tmp/handler.log') in the HTTP handler — it dominated every benchmark.
- Remove per-worker /tmp/worker.log open at thread start.
- Reorder dispatch so /baseline11|/baseline2 is checked first (baseline + pipelined + limited-conn all hit it).
- Parse Accept-Encoding with comma split + q=0 honoring instead of substring match, so 'br;q=0' no longer falsely selects brotli.
…tests - Remove read/write/keep-alive/shutdown timeout knobs from HttpServerConfig — bench runs are short and the per-connection timer arming is pure overhead here. - Drop the manual 405 in /baseline2|/baseline11 and replace the userland sum loop with array_sum() on the parsed query (matches Swoole's shape). - meta.json: remove async-db, api-4, api-16 — DB-backed profiles are not supported yet (api-4/api-16 mix in /async-db). - Delete ISSUES.md (stale).
Static-file profiles will be re-enabled once the server gains a built-in static handler (see FUTURES.md in the server repo).
The HttpArena validator probes json-tls on port 8081 (h1-over-TLS), distinct from :8443 (h2/h1 over TLS via ALPN). Without this listener all 5 json-tls checks fail. Validator: 19 → 25 passing.
- README documents architecture, listener layout, subscribed and not-yet-subscribed profiles, related TrueAsync repos. - Dockerfile FROM trueasync/php-true-async:0.7.0-alpha.3-php8.6 → 0.7.0-alpha.5-php8.6 (HTTP/2 default-enabled build, gzip middleware, bailout firewall portability fix).
Contributor
Author
|
/benchmark -f true-async-server |
Contributor
|
👋 |
Contributor
Benchmark ResultsFramework:
Full log |
The server now ships a built-in C StaticHandler with sendfile + open-file
cache + per-request precompressed sidecar selection (.br/.gz), plus a
transparent gzip/brotli compression middleware. Wire both into entry.php
and add the three profiles to the subscribed list.
- entry.php: replace the in-memory $staticFiles preload + manual AE
chooser with `addStaticHandler('/static/', '/data/static')`. Enable
the response middleware via `setCompressionEnabled(true)`.
- meta.json: subscribe to json-comp, static, static-h2.
- README: updated subscribed list (10 profiles), removed the
"not yet subscribed" entries for the three new profiles, refreshed
the dispatcher snippet.
validate.sh: 39/39 checks pass on the new image.
true-async-server: - Add /sqlite-db handler (native ext-sqlite3, prepare-once-per-worker). PDO sqlite + pool + per-request prepare measured ~14% extra instructions per request vs native (PDO core overhead: do_fetch indirection, vtable dispatch, fetch_value per column, PDOStatement object init). Native is the minimal-overhead path for read-only SQLite, and pool buys nothing here since sqlite calls are synchronous in-process. - /async-db: switch DATABASE_MAX_CONN semantics — env value is now the total budget across all worker threads; per-worker pool MAX is totalCap/workers with a hard ceiling at 4×CPU. Prevents the workers×pool_max blowup on default HttpArena env (16×256=4096 requested vs PG max_connections=256). Best measured config: 16 workers × MAX=4 → 65 PG backends → 33k RPS (was 13k with default oversubscription). - meta.json: add async-db to declared tests. swoole: - Add /sqlite-db handler (parity with true-async-server). Uses the existing SQLite.php helper which is ext-sqlite3 based with prepare-once-per-worker.
- Dockerfile: trueasync/php-true-async 0.7.0-alpha.8 → 0.7.0-alpha.11
- docker-compose.yml: mount benchmark.db into server (needed by /sqlite-db
handler and its validator tests).
- validate.sh:
- add /sqlite-db section: response shape (rating/tags/active), Content-Type
json, empty-range count=0.
- accept either text/javascript or application/javascript for .js mime
(alpha.11 ships modernised IANA-compliant default per RFC 9239).
All 41 validator tests pass on alpha.11.
Cover the two h2 static bugs we just chased: * 30 fresh-connection fetches of /static/app.js — would have caught both the worker crash (size=0 for all) and the 65535/65536 B truncation (~23% rate). * A single h2 connection multiplexing three large assets — would have caught any flow-control bookkeeping regression specific to the shared-window path. Both are tolerant of at most one transient TLS-handshake failure to stay green on slow CI, but truncations must be zero — that is the actual regression signal.
Contributor
Author
|
/benchmark -f true-async-server |
Contributor
|
👋 |
Contributor
Benchmark ResultsFramework:
Full log |
Contributor
Author
|
/benchmark -f true-async-server |
Contributor
|
👋 |
Contributor
Benchmark ResultsFramework:
Full log |
Contributor
Author
|
/benchmark -f true-async-server |
Contributor
|
👋 |
Contributor
Benchmark ResultsFramework:
Full log |
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.
Adds TrueAsync Server as an HttpArena framework entry under
frameworks/true-async-server/.What it is
A native PHP extension that runs an HTTP/1.1 + HTTP/2 + HTTP/3 server inside the PHP process — no FastCGI, no separate proxy. Built on the TrueAsync coroutine engine. One process, N event-loop threads (
SO_REUSEPORT), coroutine-per-request, ALPN-driven protocol selection.trueasync/php-true-async:0.7.0-alpha.5-php8.6tunedSubscribed profiles (7)
baseline, pipelined, limited-conn, json, upload, baseline-h2, json-tlsAll 26 validation checks pass on the published Docker image:
(Verified via
./scripts/validate.sh true-async-serveragainsttrueasync/php-true-async:0.7.0-alpha.5-php8.6.)Local benchmark snapshot
./scripts/benchmark-lite.sh true-async-server baseline-h2(h2load-c 512 -m 32 -t 8, serverWORKERS=16, 16-core WSL2 host, 5s × 3 runs):ALPN selects
h2, TLS 1.3 / AES-256-GCM throughout. Server contention with the load generator on the same host bounds the ceiling here; on dedicated 64-core hardware the number is expected to be higher.Not subscribed yet (transparent in README)
static,static-h2,static-h3— need a built-in static handler at the C level (production-tier rules forbid the user-land file cacheentry.phpwould otherwise rely on).json-comp— the server's transparent gzip middleware is in 0.7.0-alpha.5 but not yet wired intoentry.php.baseline-h2c,json-h2c— HttpArena requires port 8082 to refuse HTTP/1.1; per-listener protocol mask is on the server roadmap (currently server-wide).async-db,crud,api-4,api-16,fortunes— DB-backed; PostgreSQL adapter ships inPostgreSQL.phpbut the suite isn't fully validated yet.baseline-h3,static-h3,gateway-h3—addHttp3Listenerexists in the server, not yet enabled inentry.php.The full feature roadmap is tracked in
FUTURES.mdon the server repo. Each profile will land as the corresponding server feature does.What's in the PR
frameworks/true-async-server/Dockerfile— pulls the publishedtrueasync/php-true-async:0.7.0-alpha.5-php8.6image, adds opcache JIT settings, copiesentry.phpandPostgreSQL.php.frameworks/true-async-server/Dockerfile.local+build.sh— local-development override; copies a host-builtphpbinary andtrue_async_server.soover the published image. Not used by HttpArena CI.frameworks/true-async-server/entry.php— flat dispatcher: 8080 (h1 cleartext), 8081 (h1+TLS forjson-tls), 8443 (h1+h2+TLS via ALPN); routes/baseline11,/baseline2,/pipeline,/json/{N},/upload,/static/*,/async-db.frameworks/true-async-server/PostgreSQL.php— async PDO PostgreSQL adapter using the TrueAsync connection pool.frameworks/true-async-server/meta.json— declares the 7 subscribed profiles, tiertuned, maintainer.frameworks/true-async-server/README.md— architecture, listener layout, subscribed / not-yet-subscribed profiles, related repositories.frameworks/true-async-server/test/— local Docker-Compose smoke tests.