diff --git a/ROADMAP.md b/ROADMAP.md index 81c8deb..982ade0 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -378,3 +378,9 @@ reconnect cycles. - **Bench suite** — `urus-bench-spec.md` exists in the artefact store; wire it up once v0.2 lands (supervision changes the hot path not at all, but prove it). +- **Operator introspection via typed names** — the v0.2-era + `urus.server` / `urus.listener.{i}` pid tags were dropped in the + RFC 014 port (names are messageable endpoints now, self-registered + with a real `Sender`). If wanted back, do it properly: register the + serve loop's shutdown/control channel under a typed `urus.server` + name instead of faking pid tags with unit channels. diff --git a/src/channels/session.rs b/src/channels/session.rs index 20554c3..9dce353 100644 --- a/src/channels/session.rs +++ b/src/channels/session.rs @@ -48,8 +48,8 @@ use super::*; -use smarm::gen_server::{self, GenServer, ServerCtx}; -use smarm::{Down, ServerRef, Watcher}; +use smarm::gen_server::{self, GenServer, GenServerCtx}; +use smarm::{Down, GenServerRef, Watcher}; use std::collections::VecDeque; use std::hash::Hash; @@ -87,7 +87,7 @@ pub trait ChannelSession

: Send + 'static { pub(super) struct SessionFactory { inner: Arc>, keyfn: fn(&str, &P) -> K, - registry: ServerRef>, + registry: GenServerRef>, } /// The registry's working bounds for a session key. @@ -140,14 +140,14 @@ pub(super) struct Join { inbound: Receiver>, } -struct Registry { +struct Registry { factory: Arc>, cap: usize, ttl: Duration, sessions: HashMap>)>, /// Reverse index for `handle_down` — the reason `Key: Clone`. pid_key: HashMap, - watcher: Option, + watcher: Option>>, } impl GenServer for Registry { @@ -155,8 +155,9 @@ impl GenServer for Re type Reply = (); type Cast = Join; type Info = (); + type Timer = (); - fn init(&mut self, ctx: &ServerCtx) { + fn init(&mut self, ctx: &GenServerCtx) { self.watcher = Some(ctx.watcher()); } diff --git a/src/conn_actor.rs b/src/conn_actor.rs index 40fa3a3..c51eb2b 100644 --- a/src/conn_actor.rs +++ b/src/conn_actor.rs @@ -19,7 +19,7 @@ use crate::net::OwnedFd; use crate::parser::{self, ParseError}; use crate::plug::Pipeline; -use smarm::ServerRef; +use smarm::GenServerRef; use std::io::{self, ErrorKind}; use std::os::fd::RawFd; @@ -92,7 +92,7 @@ pub fn run_connection( fd: OwnedFd, pipeline: Pipeline, limits: ConnLimits, - registry: ServerRef, + registry: GenServerRef, ) { // The OwnedFd cleans up via Drop on any exit path (panic, error, or // normal close). No explicit close calls below. diff --git a/src/conn_registry.rs b/src/conn_registry.rs index f3d829d..267644e 100644 --- a/src/conn_registry.rs +++ b/src/conn_registry.rs @@ -33,7 +33,7 @@ //! (roadmap v0.4+), which is why it exists as its own module rather than //! being inlined into `serve`. -use smarm::{GenServer, Pid, ServerBuilder, ServerRef}; +use smarm::{GenServer, Pid, GenServerBuilder, GenServerRef}; use std::collections::HashMap; @@ -86,6 +86,7 @@ impl GenServer for ConnRegistry { type Reply = Reply; type Cast = Cast; type Info = (); + type Timer = (); fn handle_call(&mut self, request: Call) -> Reply { match request { @@ -137,8 +138,8 @@ impl GenServer for ConnRegistry { } } -pub fn start() -> ServerRef { - ServerBuilder::new(ConnRegistry::default()).start() +pub fn start() -> GenServerRef { + GenServerBuilder::new(ConnRegistry::default()).start() } // --------------------------------------------------------------------------- @@ -149,13 +150,13 @@ pub fn start() -> ServerRef { /// unwind, and panic unwind alike; the cast is infallible from the /// guard's perspective (a dead registry just returns an ignored Err). pub struct DeregisterGuard { - registry: ServerRef, + registry: GenServerRef, pid: Pid, make: fn(Pid) -> Cast, } impl DeregisterGuard { - pub fn new(registry: ServerRef, pid: Pid, make: fn(Pid) -> Cast) -> Self { + pub fn new(registry: GenServerRef, pid: Pid, make: fn(Pid) -> Cast) -> Self { Self { registry, pid, make } } } diff --git a/src/pubsub.rs b/src/pubsub.rs index 942ec12..d8b6664 100644 --- a/src/pubsub.rs +++ b/src/pubsub.rs @@ -58,7 +58,7 @@ //! # Why there is no `register(name)` helper (yet) //! //! smarm's registry maps `name → Pid`, but a `Pid` cannot be turned back -//! into a `ServerRef` (the ref *is* the inbox sender). A useful named +//! into a `GenServerRef` (the ref *is* the inbox sender). A useful named //! lookup therefore needs either smarm support (registry-held senders) //! or a process-global type-erased map here — both against the grain of //! the ratified design. Deferred; pass the handle. @@ -67,8 +67,8 @@ use std::collections::{HashMap, HashSet}; use std::fmt; use std::sync::Arc; -use smarm::gen_server::{self, GenServer, ServerCtx}; -use smarm::{channel, Down, Pid, Receiver, Sender, ServerRef, Watcher}; +use smarm::gen_server::{self, GenServer, GenServerCtx}; +use smarm::{channel, Down, Pid, Receiver, Sender, GenServerRef, Watcher}; // --------------------------------------------------------------------------- // Public handle @@ -92,7 +92,7 @@ impl std::error::Error for PubSubDown {} /// Payloads are broadcast as `Arc`: one allocation per broadcast, not /// per subscriber. pub struct PubSub { - server: ServerRef>, + server: GenServerRef>, } impl Clone for PubSub { @@ -226,7 +226,7 @@ struct Table { /// retires the entry so a reused-slot pid (fresh generation) gets a /// fresh monitor. monitored: HashSet, - watcher: Option, + watcher: Option>>, } impl Table { @@ -240,8 +240,9 @@ impl GenServer for Table { type Reply = Reply; type Cast = Cast; type Info = (); + type Timer = (); - fn init(&mut self, ctx: &ServerCtx) { + fn init(&mut self, ctx: &GenServerCtx) { self.watcher = Some(ctx.watcher()); } diff --git a/src/serve.rs b/src/serve.rs index 98ae7b5..2b08e2d 100644 --- a/src/serve.rs +++ b/src/serve.rs @@ -17,7 +17,7 @@ use crate::conn_registry::{self, Call, Cast, ConnRegistry, Reply}; use crate::net::{accept_nonblocking, bind_and_listen, OwnedFd}; use crate::plug::Pipeline; -use smarm::{ChildSpec, OneForOne, Restart, ServerRef, Strategy}; +use smarm::{ChildSpec, OneForOne, Restart, GenServerRef, Strategy}; use std::io::{self, ErrorKind}; use std::net::{SocketAddr, ToSocketAddrs}; @@ -125,7 +125,7 @@ fn listener_loop( listener: Arc, pipeline: Pipeline, limits: ConnLimits, - registry: ServerRef, + registry: GenServerRef, shutdown: Arc, ) { let fd = listener.as_raw(); @@ -327,15 +327,6 @@ pub fn serve_with_shutdown( let sf = shutdown_flag.clone(); sup = sup.child(ChildSpec::new(Restart::Transient, move || { println!("urus: listener {} starting", i); - // Named for whereis-style introspection. On a restart the - // old binding points at a dead pid; smarm's registry - // evicts stale bindings lazily, so re-registering the - // same name is fine. Ignore the result — a registry - // hiccup must not take the listener down. - let _ = smarm::register( - format!("urus.listener.{i}"), - smarm::self_pid(), - ); listener_loop(lfd.clone(), p.clone(), limits, r.clone(), sf.clone()); })); } @@ -343,11 +334,13 @@ pub fn serve_with_shutdown( // faster than that trips the cap and tears the pool down — loud // failure over a zombie server. let sup_h = smarm::spawn(move || sup.run()); - // Register via the JoinHandle's pid rather than inside the - // closure: the binding exists before the supervisor body runs a - // single instruction, so an early `whereis("urus.server")` can't - // race a None. Result ignored for the same reason as listeners. - let _ = smarm::register("urus.server", sup_h.pid()); + // The old `urus.server` / `urus.listener.{i}` name registrations + // are gone with smarm's RFC 014 registry rework: `register` is now + // `(Name, Sender)`, self-only — a name is a typed messaging + // endpoint, not a pid tag. urus's bindings were introspection-only + // with no channel behind them, so they were dropped rather than + // faked with a unit channel. A real messageable `urus.server` + // name is in the icebox (ROADMAP.md). // Block until told to shut down. We poll `try_recv` + `sleep` // rather than parking in `recv`: a smarm `Sender::send` from a @@ -399,7 +392,7 @@ pub fn serve_with_shutdown( } } - // 5. Our ServerRef drops here. The registry's inbox closes once + // 5. Our GenServerRef drops here. The registry's inbox closes once // the last conn's clone drops with it, and the runtime winds // down when the last actor exits. }); diff --git a/tests/integration.rs b/tests/integration.rs index 42e2cf3..babc2a2 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -89,24 +89,9 @@ fn hello_world() { assert_eq!(http_body(&resp), b"hello urus"); } -#[test] -fn server_and_listeners_are_registered() { - // `whereis` must run inside the runtime (the test itself is a foreign - // OS thread with no runtime in its TLS), so probe from a handler — - // connection actors live in the runtime by construction. - let pipe = Pipeline::new().plug( - Router::new().get("/whereis", |c: Conn, _n: Next| { - let ok = smarm::whereis("urus.server").is_some() - && smarm::whereis("urus.listener.0").is_some() - && smarm::whereis("urus.listener.1").is_some(); // pool of 2 - c.put_status(200).put_body(if ok { "registered" } else { "missing" }) - }) - ); - let port = spawn_server(pipe); - let resp = send_request(port, b"GET /whereis HTTP/1.1\r\nHost: x\r\nConnection: close\r\n\r\n"); - assert_eq!(http_status(&resp), 200); - assert_eq!(http_body(&resp), b"registered"); -} +// `server_and_listeners_are_registered` was deleted with the RFC 014 port: +// urus no longer binds `urus.server` / `urus.listener.{i}` names (see the +// note in serve.rs and the icebox entry in ROADMAP.md). #[test] fn echo_body() {