Tokio interval and cancel from outside

I just started learning Rust. I have a websocket server using Tokio. Now I’m trying to run something in an interval in a task, but be able to cancel the interval from the outside. The below bit doesn’t work because recv-in-a-loop-error (I hope you can see the error yourself, on a phone so don’t have the error right now). Should I be doing things differently instead? Maybe just hold a flag somewhere to be able to signal the end of the interval? Thanks, I hope the beginner question is fine over here! :slight_smile:

    let (send, recv) = oneshot::channel::<()>();

    tokio::spawn(async {
      let mut interval = time::interval(Duration::from_secs(1));
      tokio::pin!(interval);

      loop {
        tokio::select! {
          _ = interval.tick() => {
            info!("interval, do the work here");
          }
          _ = recv => {
            info!("finished, break the loop, call it a day");
            break;
          }
        }
      }

      info!("finished in the walking task");
    });

    // TODO: and use send to trigger the cancelation of the interval later on

I recommend a structure like this:

let (send, recv) = oneshot::channel::<()>();

tokio::spawn(async {
    tokio::select! {
        _ = task_inner() => {},
        _ = recv => {
            info!("finished, break the loop, call it a day");
        }
    }

    info!("finished in the walking task");
});

async fn task_inner() {
    let mut interval = time::interval(Duration::from_secs(1));
    loop {
        interval.tick().await;
        info!("interval, do the work here");
    }
}

For more details please see How to remotely shut down running tasks with Tokio.

1 Like

Thank you, this fixed it! I thought I had it figured out, but not quite yet hehe. I think the thing I was missing (but it's quite clear in the docs) was that using tokio::select! you're effectively blocking until one of the branches completes, so no need to call select continuously yourself.