Abortable tokio applications

What ergonomic ways are there to create "globally" abortable tokio server applications?

By "globally" I mean that the server creates one or more listeners, and the listener(s) may spawn N client connection tasks, and each of these should be abortable using a (single) global kill-switch.

My goal is to create a Windows service that when the user requests to "Stop" will cancel all listeners and active connections in a controlled manner.

I'm currently limiting myself to one listener and am looking to use futures' Abortable to terminate the listener task (using tokio::select! to detect the abort request), but the question is how I would propagate this to the spawned connection tasks? One solution would be to create an Abortable for each client connection task, but the client connection tasks can self-terminate, which means that the listener task would hold Abortable objects that are stale, and thus there would need to be some means for connection tasks to report back to the listener task that they are about to terminate and that their Abortable object should be released.

Another possibility might be to use a tokio::sync::broadcast channel and have the listener signal the clients that it's time to terminate, but it irks me to have to hard-code a fixed number of maximum client connections.

The canonical way that we recommend in the mini-redis example is to use a broadcast channel, see specifically the src/shutdown.rs file.

The capacity argument to tokio::sync::broadcast::channel does not limit the number of receivers. Instead, it limits how many messages each receiver may have in its buffer until the receiver skips some messages and gets the RecvError::Lagged error, which is not relevant for shutdown as you would typically not send more than one message throughout the lifetime of the broadcast channel.

1 Like