- crud is now the demonstrator: app owns smarm runtime + root supervisor,
store actor and urus::endpoint as ordered siblings (store first, so
reverse-order shutdown drains HTTP before stopping the store),
Shutdown::Infinity on the endpoint, shutdown via
rt.handle().request_shutdown(root_sup) from the stdin thread.
Deletes two kludges the old shape forced:
* static OnceLock<Sender> spawn-on-first-use -> a supervised child
that self-registers a typed Name; handlers use smarm::send per
request and turn 'between incarnations' into a 503 instead of
panicking on a dropped store.
* static SHUTTING_DOWN AtomicBool + 250ms recv_timeout poll in the
store loop and in the SSE ticker -> a plain park; the tree stops
both. Smoke-tested live: CRUD round-trips, SSE stream, clean drain
with the stream open, port closed after.
- Other examples stay short and on serve*, updated for the split config
(serve_with(cfg, smarm::Config, pipe) / serve_with_shutdown(..., signal)).
plain_serve's URUS_SCHED_THREADS now builds a smarm::Config.
ws_chat's doc block explains the OnceLock is a serve*-only workaround
and points at crud for the clean shape.
- README: new 'Your Own Supervision Tree' section (endpoint as the real
API), graceful shutdown reframed as the serve*-only path, Config table
loses scheduler_threads and gains name, PubSub rule 1 notes the
supervised-sibling alternative.
111 lib + 50 integration + 2 doc tests green; clippy clean.
54 lines
2.3 KiB
Rust
54 lines
2.3 KiB
Rust
//! Plain benchmark server: the `load_profile` request path with zero causal
|
|
//! machinery — the baseline half of the ka/close A/B matrix (the
|
|
//! throughput-inversion chase).
|
|
//!
|
|
//! Identical route, handler, and `Config` construction to `load_profile`;
|
|
//! differs only in having no `smarm-causal` feature, no sweep, and no
|
|
//! shutdown path — it serves until killed. Throughput is measured
|
|
//! externally (wrk).
|
|
//!
|
|
//! Env:
|
|
//! URUS_PORT listen port (default 8080; binds 0.0.0.0)
|
|
//! URUS_SCHED_THREADS smarm scheduler OS threads (default: smarm's own
|
|
//! default). Malformed values panic rather than
|
|
//! silently falling back — a benchmark knob that
|
|
//! quietly reverts to default poisons the cell.
|
|
//!
|
|
//! cargo run --release --example plain_serve
|
|
|
|
use std::net::SocketAddr;
|
|
|
|
use urus::{serve_with, Config, Conn, Next, Pipeline, Router};
|
|
|
|
/// Mirrors `load_profile`'s handler byte for byte: param parse + JSON render.
|
|
fn json_id(conn: Conn, _next: Next) -> Conn {
|
|
let id: u64 = conn.params.get("id").and_then(|s| s.parse().ok()).unwrap_or(0);
|
|
conn.put_status(200)
|
|
.put_header("content-type", "application/json")
|
|
.put_body(format!("{{\"id\":{id}}}"))
|
|
}
|
|
|
|
fn main() {
|
|
let port: u16 = std::env::var("URUS_PORT")
|
|
.ok()
|
|
.and_then(|v| v.parse().ok())
|
|
.unwrap_or(8080);
|
|
let addr: SocketAddr = format!("0.0.0.0:{port}").parse().expect("addr");
|
|
let sched_threads: Option<usize> = std::env::var("URUS_SCHED_THREADS").ok().map(|v| {
|
|
v.parse()
|
|
.unwrap_or_else(|_| panic!("URUS_SCHED_THREADS not a usize: {v:?}"))
|
|
});
|
|
// Audit line: lands in each bench cell's server.log so the effective
|
|
// scheduler count is recorded per cell, same discipline as mode-verify.
|
|
eprintln!("plain_serve: scheduler_threads={sched_threads:?}");
|
|
// Scheduler threads are a RUNTIME knob, so they live in smarm::Config,
|
|
// not urus's — an endpoint placed in someone else's tree could not
|
|
// honour them anyway.
|
|
let rt_cfg = match sched_threads {
|
|
Some(n) => smarm::Config::exact(n),
|
|
None => smarm::Config::default(),
|
|
};
|
|
let pipe = Pipeline::new().plug(Router::new().get("/json/:id", json_id));
|
|
serve_with(Config::new(addr), rt_cfg, pipe).expect("serve");
|
|
}
|