Lifecycle and graceful shutdown
serve() returns a Server with three members:
| Member | Description |
|---|---|
addr | Promise<{ hostname, port }> — resolves once the server is listening |
stop() | Stop accepting new connections and shut down |
finished | Promise<void> — resolves when the accept loop has ended |
Call await server.stop() for graceful shutdown. In-flight requests are allowed to finish; no new connections are accepted after stop() resolves.
JavaScript
import { serve } from "runtime:http"; const server = serve({ port: 8080 }, (req) => new Response("ok")); const { port } = await server.addr; // … run until a signal or condition … await server.stop(); await server.finished; console.log("server stopped");
Shutdown on ^C / SIGTERM
esrun handles this for you: it stops accepting, lets in-flight requests answer, and exits 130 / 143.
| Situation | What happens |
|---|---|
| A server is running | Drain in flight, then exit 128 + signal |
| No server is running | Exit immediately |
| You installed a handler | esrun stays out of the way |
Second ^C while draining | Exit immediately |
Drain outlasts --shutdown-grace | Exit anyway (default 10000ms) |
For your own cleanup, take it over with onSignal:
JavaScript
import { onSignal, offSignal } from "runtime:process"; const shutdown = async (signal) => { offSignal(signal, shutdown); await server.stop(); await pool.close(); }; onSignal("SIGINT", shutdown); onSignal("SIGTERM", shutdown);