Async "shutdown signal" implementation

I'm implementing a type for telling multiple async tasks to shut down. Requirements:

  • Function that returns a (ShutdownSender, ShutdownReceiver) pair
  • ShutdownSender doesn't need any methods. When you drop it, that signals that it's time for shutdown.
  • ShutdownReceiver is Clone so multiple tasks can wait for the same shutdown signal.
  • ShutdownReceiver has a method async fn recv(&self) that waits for the signal to be sent.
  • recv is cancel-safe.
  • After recv is successfully awaited the first time, it's OK to call it again; it just returns right away.

I've implemented it using a Tokio watch channel, and that works fine, but I'm not using most of a watch channel's features. Also, my implementation of recv has to clone the receiver (to satisfy the non-mut part of requirement 4 and I think also requirement 6), which bumps a refcount. That seems unnecessary. (Admittedly, the perf probably isn't worth worrying about, even though we do call recv() in lots of select! loops.)

Is there a better primitive to use here? Is there a crate that does exactly what I want?

Isn't this a CancellationToken?

1 Like

Or the generic AbortHandle in futures::future - Rust

I think both of these just drop the async task though, so you'll need to use a drop guard if you want that - and there's no async drop yet

Edit: ah, the tokio one is a bit fancier it looks like

Yes!! Thank you.