Tokio select but not cancling the several tasks within the future?

i need to do something like this:

loop
{
    tokio::select!
    {
        // 1 wait for a shutdown signal, break loop when received
        // 2 listen for connections on TCP as a server and spawn each handling of a client as a task (client tasks) 
    }
} // How can I break the loop upon shutdown, but not have the client tasks aborted/canceled (select! goes through and does that recursively i guess)

if you are talking about the spawned tasks handling client connections, no, select! doesn't cancel them, it only cancels the other alternative futures (not spawned tasks) of the select!, in this case the TCP listener.

if your loop is in the async fn main() {} task, it is the return from the "main" task that tears down the tokio runtime, which forces all unfinished tasks to cancel.

your "main" task must not return before you gracefully shutdown the client handler tasks. you have multiple ways to do this, examples includes:

  • keep track how many client handlers are alive using some synchronized counter, the main task will only return when the counter reaches zero.
    • one trick is to (ab-)use the internal counter of a mpsc channel:
      • the main task create a pair of Sender and Receiver
      • each spawned task get a clone of the Sender end, which will be dropped when they finishes
      • when the main task finishes, it drops its Sender and await the Receiver
      • once the count of the Senders reaches zero, the Receiver will be waken
  • don't discard the join handles after spawning the tasks, await them before returning from "main".
    • JoinSet can be used, instead of manually keeping track of all the join handles

this is under the assumption that you want the client handler to finish. if you don't want to wait for all of them to finish because it might takes long, you must implement some from of cooperative cancellation mechanism, e.g. using tokio_util::CancellationToken.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.