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
1 Like

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.

2 Likes

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.

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.