Make shutdown event-driven and address review findings
Replace the non-blocking accept + 50ms poll with a plain blocking accept(). A signal-hook thread waits for SIGTERM/SIGINT, sets a flag, and wakes accept() with a throwaway connection to the socket. On shutdown the listener is closed and the socket file unlinked before the grace period, so clients that connect late fail fast with ENOENT instead of queueing and being reset. In-flight handlers are tracked by a counter + Condvar rather than a Vec of JoinHandles. Accepted streams now get a 5s read/write timeout so a silent client cannot pin a handler thread or stretch every shutdown to the full grace period. Transient accept() errors are logged and retried instead of exiting the daemon. A second SIGTERM/SIGINT during the grace period forces an immediate exit with status 1. Tests: wrap the child in the kill-on-drop guard immediately after spawn, drop the redundant wall-clock assertion, and add a case for a client that connects but never sends. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kmrgkpp9YBJ6AMaWYPPZuD
This commit is contained in:
@@ -56,11 +56,14 @@ rejected before touching the filesystem. `service` and `realm` are read but igno
|
||||
### Server lifecycle (`server/src/server.rs`)
|
||||
|
||||
Startup removes any stale file at the socket path, binds, and chmods the socket 0777.
|
||||
The accept loop is non-blocking and polls a flag set by `signal-hook` for SIGTERM/SIGINT.
|
||||
On a signal it stops accepting, waits up to 3 s for in-flight handler threads, then
|
||||
`Drop` removes the socket file. Exit status is 0. This matters because as container
|
||||
PID 1 the process gets no default signal handling; without it `docker stop` hangs for
|
||||
10 s and host reboots stall.
|
||||
The accept loop is a plain blocking `accept()`. A `signal-hook` thread waits for
|
||||
SIGTERM/SIGINT; on the first one it sets a shutdown flag and makes a throwaway
|
||||
connection to the socket to wake the accept loop, which then closes the listener,
|
||||
unlinks the socket file, and waits up to 3 s for in-flight handler threads before
|
||||
exiting 0. A second signal exits immediately with status 1. Accepted streams get a 5 s
|
||||
read/write timeout so a silent client cannot pin a thread. This matters because as
|
||||
container PID 1 the process gets no default signal handling; without it `docker stop`
|
||||
hangs for 10 s and host reboots stall.
|
||||
|
||||
CLI options live in `options.rs` as a `LazyLock<Opt>` (clap derive) and are read from
|
||||
anywhere via `OPTIONS`.
|
||||
|
||||
Reference in New Issue
Block a user