How do I shut a server down from a handler when only its owner may close it?
← Error Handling and Exceptions · Ref: Q1700
Call the server's stop(). A server that serves in a loop - TCP's accept(handler) and acceptUntilComplete(handler, readyHandler), HTTP's serve() and serveUntilComplete(readyHandler) - runs until stop() is called, from a connection handler, a signal handler or a control connection, on any thread. stop() ends serving WITHOUT closing: accept() or serve() returns true, and the server stays set, still open and still owned, until the try that made it ends and closes it.
A handler cannot close the server instead. The handler captured the server, and a capture belongs to the scope that made it - the try, whose generated close closes it. There is no 'close' statement (E01094), and 'server.close()' is E81060: closing it in the handler would close it twice (once in the handler, once when the try ends) and would close it while accept() was still using it. Only the owner closes; everyone else stops.
The program below makes the server a try-with-resources resource. Its handler reads one request and, on 'shutdown', calls server.stop(). A client connects before accept() is called - a TCP server listens from construction, so the connection waits in the backlog - and accept() serves it and then returns. The program prints that the server is still set after accept() returns, and the end of the try closes it.
For HTTP the shape is the same: make the HTTP a try resource, call httpServer.serve(), and call httpServer.stop() from a signal handler (Signals().register) or an admin operation; serve() returns once in-flight requests have drained, and the try closes the server. A stopped server cannot serve again - make a new one.
acceptUntilComplete and serveUntilComplete stop the server for you when their ready handler (a TCPReadyHandler / HTTPReadyHandler, or a pure TCPReadyObserver / HTTPReadyObserver) ends - normally, by Exception or by Panic - and they too only stop it: the try still closes it. See Q1760.
Example
defines module qa.errorhandling.stopaserver defines function sendShutdown() -> port as Integer loopback <- Networking().loopbackV4() try -> connection <- TCP(NetworkProperties(loopback, port)).connect() if connection? connection.output().println("shutdown") defines program StopFromAHandler() stdout <- Stdout() port <- 28207 try -> server <- TCP(NetworkProperties(port: port, backlog: 2, maxConcurrent: 2, localOnly: true)) stopOnRequest <- (server, stdout) is TCPHandler as function request <- input.next() stdout.println(`handler received ${request}`) if request == "shutdown" server.stop() sendShutdown(port) served <- server.accept(stopOnRequest) stdout.println(`accept returned ${served}, server still set ${server?}`) stdout.println("the try has closed the server")
Common mistakes
E81060 — The handler captured the server, and a capture belongs to the try that made it, which closes it. Closing it in the handler would close it twice, and while accept() was still serving. Call server.stop() - it ends accept() without closing. See ek9 -h E81060 for details.
Incorrect:
if request == "shutdown" server.close()
Correct:
if request == "shutdown" server.stop()
Other ways to ask this
- How do I stop a TCP server from inside its connection handler?
- How do I end HTTP serve() from a signal handler or admin endpoint?
- What is the difference between stop() and close on a server?
- Why can a handler not close the server it captured?
- How does accept() return so the program can exit?
Coming from another language?
Java: ServerSocket.close() from another thread both ends accept() and releases the socket, so any code holding the server can shut it down - and the try-with-resources that owns it closes it again. Jetty/Undertow separate stop() from destroy(). Go: http.Server.Shutdown(ctx) stops serving and Close() releases. Rust (tokio): a shutdown signal ends the accept loop; the listener is dropped by its owner. EK9: stop() ends serving and only the owner closes - 'server.close()' is E81060.
Keywords: owner, HTTP, accept, stop, TCP, server, E81060, serve, close, shutdown, handler