Container runtimes and process supervisors stop a process by sending
SIGTERM. Revali catches it, reports itself unready, stops accepting new
connections, waits for the requests already being served, and only then exits.
Without that, every deploy and every scale-down truncates whatever responses happened to be mid-flight — the client sees a dropped connection rather than the answer it was about to get.
You get this by default. There is nothing to enable.
What happens on SIGTERM#
-
Readiness starts reporting
503immediately, while the server is still accepting. SeedrainDelay— this window exists so a load balancer can notice and steer away, and requests arriving during it are served and tracked normally rather than refused. - Once the window closes the listening socket does, so no new connection is taken.
- Requests already in flight keep running and send their responses.
-
onServerStoppedruns, so the app can release what it owns. - The process exits with status
0.
If requests are still running when shutdownTimeout
elapses, the wait is abandoned and shutdown continues — a stuck handler cannot
keep the process alive forever.
SIGINT (Ctrl-C) follows the same path. A second signal while a shutdown is
already running is ignored rather than starting a second one.
shutdownTimeout#
How long to wait for in-flight requests. Defaults to 15 seconds.
@App()
final class MyApp extends AppConfig {
const MyApp() : super(host: 'localhost', port: 8080);
@override
Duration get shutdownTimeout => const Duration(seconds: 25);
}
Releasing resources#
Override onServerStopped to close what the app owns — database pools,
message consumers, file handles. It runs after in-flight requests have
finished, so nothing still serving a request has its connection pulled out
from under it.
@App()
final class MyApp extends AppConfig {
const MyApp() : super(host: 'localhost', port: 8080);
@override
Future<void> onServerStopped() async {
await database.close();
}
}
Throwing from onServerStopped is logged and does not stop the shutdown.
Owning signal handling yourself#
Set handleShutdownSignals to false if something else in your process
already installs handlers, or you want to sequence shutdown differently:
@override
bool get handleShutdownSignals => false;
Nothing else changes — the server simply stops listening for signals, and exiting becomes your responsibility.
What's next?#
-
Create an App — the rest of
AppConfig -
revali build— produce the executable that receives these signals