Code:
use std::thread;
use chrono::Utc;
use tokio::sync::watch::Receiver;
use std::time::Duration;
use tokio::sync::watch;
use tokio::time::sleep;
pub fn get_now_formatted() -> String {
Utc::now().format("%Y-%m-%d %H:%M:%S.%3f").to_string()
}
#[tokio::main]
async fn main() {
let mut rx = subscribe_orderbook().await;
// simple thread that reads from the stream
tokio::spawn(async move {
loop {
println!("{}: Trying to read..", get_now_formatted());
rx.changed().await.expect("TODO: panic message");
println!("DOESN'T READ PROPERLY UNLESS WE COMMENT OUT AWAIT LINE IN SENDER");
println!("{}: Received: {:?}", get_now_formatted(), rx.borrow().clone());
}
});
loop {
sleep(Duration::from_millis(1000)).await;
}
}
pub async fn subscribe_orderbook() -> Receiver<i32> {
// this is where the issue will happen:
let (channel_tx, channel_rx) = watch::channel(1);
tokio::spawn( async move {
let mut counter = 0;
loop {
counter += 1;
let result = channel_tx.send(counter);
if result.is_err() {
eprintln!("{} Failed to send fair value to main thread: {}", get_now_formatted(), result.err().unwrap());
}
else {
println!("{} SENT {:?}", get_now_formatted(), counter);
}
// NOTE: commenting out this pointless await fixes the problem!
// sleep(Duration::from_millis(0)).await;
}
});
channel_rx
}
- It prints only one "Received.." despite printing many "SENT".
- I can fix it by commenting out the line
sleep(Duration::from_millis(0)).await
Essentially, this only works if the sender task has an "await" somewhere in its closure. This is what I discovered after many hours of digging and distilled it into this example code.
Note that this is specific to the sender task. If I create a separate task that loops forever, it does not cause any issues. Meaning, adding the following to the main function does not cause problems:
// NOTE: Let's add a task that blocks forever... does not make any difference to either case
tokio::spawn(async move {
loop {
thread::sleep(Duration::from_millis(1000));
}
});
Why does adding any "await" in the sender work, and is it "correct" to simply add that pointless sleep for 0 ms line as a workaround?
Thank you
EDIT:
It seems like just adding an "await" is not enough because it introduces strange delays.