Repository navigation
v1.0.0
ONRouter 1.0.0 — the first release whose deliverable is "run it in production", not just "speak the config": CPU affinity, outage resilience, canary splitting, a WASM plugin host, CI, a 21-minute soak and two handbooks.
What's new
CPU affinity — worker_threads + worker_cpu_affinity
worker_threads N; sizes the runtime, and worker_cpu_affinity auto|off|<hex masks>; pins each
worker to a core or a core set: Linux sched_setaffinity, Windows SetThreadAffinityMask, and on
macOS — where no hard thread affinity exists — the gateway says so instead of pretending. Masks
rotate when there are more cores than workers, and -t prints the per-thread plan before the
process ever accepts a connection, so the binding is reviewable in code review rather than
guessed from top.
Resilience — circuit_breaker and lazy_rejoin
circuit_breaker errors=… window=… open=…;adds the closed → open → half-open machine on top of
the existing passivemax_fails/fail_timeoutremoval. Failures count consecutively inside the
window: one success in between resets the tally.lazy_rejoin <interval>;makes an ordinary user request the recovery probe. A dead backend is
carried by the remaining servers, the next real request doubles as the trial, and a success puts
the node back — no separate health-check traffic to budget for.- Metrics:
onrouter_upstream_server_availablenow reports what the scheduler may actually pick
(manualdown, passive removal, open circuit), whileonrouter_upstream_server_healthystays
purely the active check verdict — with nohealth_checkconfigured it never leaves 1, which is
exactly why the alerting guidance moved toavailable. Also new:
onrouter_upstream_lazy_probes_total,onrouter_upstream_circuit_state,
onrouter_upstream_circuit_trips_total.
Canary / grey release
canary $var "<sticky key>" { cookie …; header …; arg …; ua ~* …; os …; percent …; default …; }
selects a whole declared upstream per request — first match wins, and the sticky key keeps one user
on one version instead of bouncing between two. $proxy_split / $proxy_split_served plus
proxy_split_failover on|off|http://target turn a cross-version failover into a visible ledger line
rather than a silent 200, and the response cache is keyed by the branch that served it.
WASM gateway plugins
wasm_plugin <name> <file.wat|file.wasm> [fuel=…] [memory=…]; plugged into access_by_wasm,
header_filter_by_wasm and body_filter_by_wasm. A small stable host ABI exposes request/response
headers, status and body; fuel and a memory cap bound a bad module's blast radius, and traps fail
closed — a broken plugin cannot quietly pass traffic through unmodified.
Verification
cargo test --workspace→ 482/482 (469onrouter-server+ 13onrouter-config);
cargo clippy --workspace --all-targets→ no errors.- Five real-traffic E2E suites → 145/145:
canary_e2e22/22,wasm_e2e23/23,
resilience_e2e17/17 (passive removal, lazy rejoin driven by a real request, circuit
open → half-open → recovered,server_available),affinity_e2e7/7,proxy_split_e2e76/76. conf/tutorial_full.confend to end → 33/33 (static, canary conditions/percent/stickiness,
proxy path rewrite, cache MISS→HIT, WASM, Lua shared dict, circuit 502 + half-open recovery,
lazy rejoin).- 21-minute soak: PASS — 2,591,305 requests, 0 failures, 20.92 min, 2064.7 req/s, backend
hits 1,963,093; private memory 20.11 → 21.97 MiB (+1.86 MiB, slope +0.067 MiB/min against a
1 MiB/min gate), peak 22.15 MiB. An earlier run of the same configuration added +2.19 MiB over
2,787,193 requests, so the growth tracks warm-up, not elapsed requests. tools/release_verify.pyon the extracted package → 26/26, including the front_proxy
recognise-but-do-not-trust split and the provider-name grep over the packaged binary
(controlsfront_proxy49 /auto_trust10).- GitHub Actions
CIon this commit: unit + clippy + the five suites, success.
Downloads / assets
Per-platform archives built by release.yml (onrouter + orr-gencert, plus SHA256SUMS.txt).
Note the honest gap: those workflow assets still carry only the two executables. The runnable
directory — conf/*.conf, the wasm/wasm_static/soak_static trees, lua/, public/, both
docs, and a certs/ pair generated at package time so a fresh extract passes
onrouter -t -c conf/onrouter.conf — is what build-release.sh / build-release.ps1 produce in
the tree; wiring release.yml to that same staging is the follow-up for the next tag.
Documentation
docs/OPERATIONS.md— the operator half: every 1.0 directive with its default and the failure
it guards against, ports/TLS/cert placement, affinity and topology reading, resilience and canary
wiring, cache/Lua/WASM limits, metric families with the alerts that useserver_available,
the-tcontract, hot reload, upgrade/rollback (binary hot upgrade viaUSR2is still not
implemented — roll or blue-green), and the pre-release checklist.docs/TUTORIAL.md— the build-it-up half:conf/tutorial_hello.confto
conf/tutorial_full.conf, feature by feature, with the commands and the metrics that prove each
step actually took.
中文摘要
1.0.0 把“能跑配置”升级成“能上线”:worker 线程绑定 CPU 核心(Linux/Windows 生效,macOS 明确说明不支持,
-t 会打印每线程的绑定计划);circuit_breaker 熔断叠加原有被动摘除,lazy_rejoin 让真实用户请求充当
恢复探针,宕机后端由其他服务器分担、恢复后自动加回;canary 按 cookie / header / 参数 / UA / 系统 /
百分比把整条 upstream 版本发给用户,粘性键保证同一人不来回跳版本,跨版本 failover 在账本里可见;
wasm_plugin 在 access / header_filter / body_filter 三个相位接管网关,带 fuel 与内存上限,出错一律 fail-closed。
新增 onrouter_upstream_server_available 表达“此刻可被调度”,与只反映主动健康检查的 server_healthy 分工。
验证:单元 482/482,五组真实流量 E2E 145/145,教程配置端到端 33/33,发布包 release_verify 26/26,
21 分钟压测 PASS(2,591,305 请求、0 失败、2064.7 req/s,私有内存 +1.86 MiB、斜率 +0.067 MiB/min)。
运维手册与使用教程分别在 docs/OPERATIONS.md、docs/TUTORIAL.md。
Full Changelog: v0.7.0...v1.0.0