Tokio: how to handle end of channel in `select!`?

I has two channels to read:

       let (stat_tx, mut stat_rx) = tokio::sync::mpsc::channel(10);
       let (main_tx, mut main_rx) = tokio::sync::mpsc::channel(1_000);

I want read from stat_rx and main_rx until main_rx.recv() return None.

And I can not understand what if stat_rx.recv() return None before main channel return None, how tokio::select! handle it?

loop {
    tokio::select! {
                stat = stat_rx.recv() => {
                    if let Some(something) = stat {
                        //handle statistic
                    }
                }
                Some(res) = main_rx.recv() => {
                   // handle event from main channel
                }
                else => break,
    }
}

when stat_rx.recv() return None, tokio stops poll stat_rx or may be it execute else branch?

It does neither but just continues polling the receiver of the stat_rx channel endlessly for new messages, even after the channel is closed and only None is returned. Example.

How about this instead then?

    loop {
        tokio::select! {
            Some(stat) = stat_rx.recv() => {
                println!("received stat: {stat:?}");
            }
            main = main_rx.recv() => {
                if let Some(res) = main {
                    println!("received on main: {res}");
                } else {
                    println!("canceling loop");
                    break;
                }
            }
        }
    }

Playground.

3 Likes