Skip to content

Commit e73221d

Browse files
authored
Add renderer transport probe (#3784)
## Summary - add benchmark-only probe comparing Fastify h2c TCP, native `node:http2` h2c TCP, and native `node:http2` over Unix socket - document the probe under `react_on_rails_pro/scripts/load` - keep production renderer defaults/config untouched Refs #3582 Refs #3583 ## Codex Decision Log - Kept this as Phase 0 evidence only; no Fastify replacement or UDS production transport is selected here. - Added cleanup/body-limit safeguards so custom payload and skip-UDS runs do not produce misleading results or remove caller-owned files. - Local benchmark evidence is macOS/same-host microprobe only; Linux/topology validation against the real renderer harness remains required before product decisions. ## Local benchmark note Full local probe at `/tmp/ror-transport-probe-full` (3000 requests, 300 warmup, zero failures): - small_unary p95: Fastify TCP 0.806ms, native TCP 1.090ms, native UDS 0.392ms - stream_16kb p95: Fastify TCP 0.762ms, native TCP 0.729ms, native UDS 0.444ms ## Validation - `bundle exec rspec spec/load/transport_probe_spec.rb` - `bundle exec ruby scripts/load/transport_probe.rb --requests 1 --warmup 0 --body-bytes 1048577 --stream-bytes 1024 --scenarios fastify_tcp --output-dir /tmp/ror-transport-probe-large-body-current` - `bundle exec ruby -c scripts/load/lib/transport_probe.rb` - `node --check scripts/load/transport_probe_server.mjs` - `bundle exec rubocop --ignore-parent-exclusion scripts/load/lib/transport_probe.rb scripts/load/transport_probe.rb spec/load/transport_probe_spec.rb` - `pnpm exec prettier --check react_on_rails_pro/scripts/load/README.md react_on_rails_pro/scripts/load/transport_probe_server.mjs` - `pnpm exec eslint react_on_rails_pro/scripts/load/transport_probe_server.mjs` - worker also ran `bundle exec rspec spec/load/` - `codex review --base origin/main` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Benchmark-only tooling under `scripts/load` with no production transport or renderer behavior changes; risk is limited to monorepo workspace/lockfile updates and local probe execution. > > **Overview** > Adds a **benchmark-only** renderer transport probe under `react_on_rails_pro/scripts/load` to gather Phase 0 evidence for issues #3582/#3583. It does **not** change production renderer defaults, Rails HTTP clients, or runtime transport configuration. > > A Ruby CLI (`transport_probe.rb` + `lib/transport_probe.rb`) spawns a small Node server (`transport_probe_server.mjs`), drives HTTP/2 probe traffic via `Async::HTTP`, and compares **Fastify h2c TCP**, **native `node:http2` h2c TCP**, and **native HTTP/2 over Unix domain sockets** on `small_unary` and `stream_response` workloads. Results include latency percentiles, RPS, failure counts, baseline selection (`fastify_tcp` preferred, else `native_tcp`), and per-scenario deltas; output goes to `transport_probe_summary.json` under `tmp/load-tests/transport-probe/`. > > Monorepo wiring adds `react_on_rails_pro` and `react_on_rails_pro/scripts/load` to pnpm workspaces with a private `fastify` devDependency. The load README documents usage, `--skip-uds`, body-limit semantics, and benchmark caveats. A large RSpec suite covers config parsing, summary math, Node readiness validation, and Node server edge cases (body limits, socket path safety, aborted streams). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 5e927ff. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **New Features** * Added HTTP/2 transport probe tool for benchmarking request performance across Fastify, native HTTP/2, and Unix domain socket transports with configurable request counts and payload sizes. * **Documentation** * Added transport probe documentation with setup instructions, command-line options, and output file location details. * **Tests** * Added comprehensive test suite for transport probe functionality and edge cases. * **Chores** * Updated monorepo workspace configuration to include react_on_rails_pro package. <!-- end of auto-generated comment: release notes by coderabbit.ai --> ## Agent Merge Confidence Mode: accelerated-rc Score: 9/10 Auto-merge recommendation: yes Affected areas: Pro benchmark tooling, Node renderer transport research, monorepo workspace metadata CI detector: `script/ci-changes-detector origin/main` -> JavaScript/TypeScript plus uncategorized changes; full suite and benchmarks recommended Validation run: - `cd react_on_rails_pro && bundle exec rspec spec/load/transport_probe_spec.rb` -> 31 examples, 0 failures - `cd react_on_rails_pro && bundle exec rubocop scripts/load/transport_probe.rb scripts/load/lib/transport_probe.rb spec/load/transport_probe_spec.rb` -> no offenses - `pnpm exec eslint react_on_rails_pro/scripts/load/transport_probe_server.mjs` -> pass - `pnpm exec prettier --check react_on_rails_pro/scripts/load/transport_probe_server.mjs` -> pass - `script/check-pro-license-headers --self-test && script/check-pro-license-headers --check` on a temporary merge with `origin/main` -> pass - `script/ci-changes-detector origin/main` -> full suite + benchmarks recommended Review/check gate: - Claude review: complete for `5e927ff82805e8cfb256c28261b7c07629282f6a`, no unresolved review threads - Cursor Bugbot: complete for `5e927ff82805e8cfb256c28261b7c07629282f6a` - GitHub checks: complete for `5e927ff82805e8cfb256c28261b7c07629282f6a`; skipped benchmark confirmation/report rows, docs-format-check, and legacy Claude Code job are expected non-running paths Known residual risk: low; this is benchmark-only tooling and does not change production renderer transport defaults Finalized by: Claude Code Review check `claude-review` SUCCESS for `5e927ff82805e8cfb256c28261b7c07629282f6a` (GitHub Actions job 80367689384)
1 parent 9bd5482 commit e73221d

9 files changed

Lines changed: 1562 additions & 0 deletions

File tree

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
"packages/react-on-rails-pro-node-renderer",
1111
"packages/create-react-on-rails-app",
1212
"react_on_rails/spec/dummy",
13+
"react_on_rails_pro",
14+
"react_on_rails_pro/scripts/load",
1315
"react_on_rails_pro/spec/dummy",
1416
"react_on_rails_pro/spec/execjs-compatible-dummy"
1517
],

pnpm-lock.yaml

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
packages:
22
- 'packages/*'
33
- 'react_on_rails/spec/dummy'
4+
- 'react_on_rails_pro'
5+
- 'react_on_rails_pro/scripts/load'
46
- 'react_on_rails_pro/spec/dummy'
57
- 'react_on_rails_pro/spec/execjs-compatible-dummy'

react_on_rails_pro/scripts/load/README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,55 @@ requests before measured requests begin. All workers must finish warmup before m
5454
`--start-gate-timeout` controls how long to wait for them (default: 30 seconds). If bundle upload is
5555
slow on a cold renderer, adjust `--upload-timeout` (default: 10 seconds).
5656

57+
### Transport Probe For Fastify/Native HTTP/2/UDS
58+
59+
Issues #3582 and #3583 need benchmark evidence before any production renderer
60+
transport change. The benchmark-only transport probe starts a tiny local Node
61+
server with equivalent probe endpoints over:
62+
63+
- Fastify h2c over TCP loopback.
64+
- Native `node:http2` h2c over TCP loopback.
65+
- Native `node:http2` over a Unix domain socket.
66+
67+
It does not change the production renderer, the Rails HTTP client, or the
68+
default h2c-over-TCP transport.
69+
70+
Run from `react_on_rails_pro/` after workspace Node dependencies are installed:
71+
72+
```bash
73+
bundle exec ruby scripts/load/transport_probe.rb --requests 3000 --warmup 300
74+
```
75+
76+
Use Node >= 18, matching the Pro package requirement. The native stream probe
77+
uses Node's `Readable#iterator` API.
78+
79+
`--body-bytes` is both the request payload size sent by each probe request and
80+
the server-side body limit. For example, `--body-bytes 1048576` sends a 1 MB
81+
request body and rejects requests larger than 1 MB. Normal benchmark requests
82+
send exactly the configured limit, so rejection testing requires a separate
83+
oversized request rather than a standard probe run.
84+
85+
When comparing `stream_response` deltas, remember that Fastify enforces
86+
`bodyLimit` before the handler sees the request, while the native HTTP/2 stream
87+
handler reads the request body before writing the response. Treat that difference
88+
as part of the benchmark interpretation rather than production transport proof.
89+
90+
For environments where Unix sockets are unavailable:
91+
92+
```bash
93+
bundle exec ruby scripts/load/transport_probe.rb --skip-uds
94+
```
95+
96+
The probe writes `transport_probe_summary.json` under
97+
`tmp/load-tests/transport-probe/<timestamp>/`. Treat this as Phase 0 evidence
98+
only: a production UDS transport still needs Linux/topology validation against
99+
the real renderer harness (`bin/renderer-harness`) before adding socket-path
100+
configuration or runtime transport plumbing.
101+
102+
Summary JSON records the latency-delta baseline in the top-level `baseline`
103+
field. `fastify_tcp` is preferred when selected; if it is omitted, the probe
104+
falls back to `native_tcp` as the baseline.
105+
57106
### Tracking the node-renderer process
58107

59108
To include the node-renderer RSS in `memory.csv`, pass its PID:

0 commit comments

Comments
 (0)