Skip to content

Graceful stop on SIGTERM

wired_server_run installs a SIGTERM handler before serving (RFC 9114 5.2): on receipt, new connections stop being accepted, GOAWAY goes out once to every still-live connection, and the process exits once every connection has drained or a bounded grace period elapses. wired_srvworkers_run (the --workers fan-out behind wired_srvdriver_run) layers a supervisor on top: it forwards the one SIGTERM to every live worker and stops respawning crashed ones, so the whole process group still winds down together.

This page runs one worker (--workers 1), answers a request, then is sent SIGTERM.

Code

main.c
#define WIRED_MAIN
#include "wired.h"
static int on_request(
void* ctx,
const wired_h3reqdrive_req* req,
u64 offset,
wired_obuf* body_out,
const char** content_type,
int* more,
u64* total_size) {
(void)ctx;
(void)req;
(void)offset;
(void)more;
(void)total_size;
*content_type = "text/plain";
wired_obuf_printf(body_out, "ok");
return 1;
}
int wired_main(int argc, char** argv) {
/* The same fixed demo identity as the HTTP/3 hello page. */
static wired_srvboot_demo_keys keys;
wired_srvboot_id id;
wired_srvboot_demo(&id, &keys, 0x50, "guide-h3");
/* --port, --workers, --cores, --ifindex, ... pick and configure a driver. */
wired_srvdriver_opt opt = {0};
if (!wired_srvdriver_parse(argc, argv, &opt)) {
wired_log_str("bad flags\n");
return 2;
}
wired_srvrun_handler h = {.cb = on_request};
wired_srvrun_obs obs = {0};
return wired_srvdriver_run(&id, h, obs, &opt) < 0 ? 1 : 0;
}

Output

Terminal window
$ ./ops-shutdown --port 4433 --workers 1
conn closed by peer (CONNECTION_CLOSE)
Terminal window
$ probe h3get 127.0.0.1:4433 /
GET / status=200 content-type=text/plain body="ok"
  • wired_srvdriver_parse/wired_srvdriver_run pick the driver from argv the same way ops/handshake-knobs does; --workers 1 selects wired_srvworkers_run with exactly one forked child.
  • The supervisor’s own SIGTERM handler only sets a flag (async-signal-safe); the reap loop forwards SIGTERM to every live worker’s pid exactly once and stops re-forking a replacement for a worker that exits — a crash during shutdown is not respawned.
  • Each worker’s own copy of wired_server_run runs unmodified: it is the SIGTERM the supervisor forwards that drives its own graceful-shutdown path (no new connections, GOAWAY, drain-then-exit) described above.
  • --workers beyond 1 is not exercised here: more than one worker shares the port through SO_REUSEPORT’s kernel-side hash alone, with no per-worker steering, which wired_srvworkers_run’s own doc flags as an intermittent-handshake risk under this fork model. --workers 1 sidesteps that while still exercising the real supervisor/forward/reap path.