0

I wrote this code, but when sending pings, the program cannot do anything else. How can I spawn another thread to do this work while I do something else in my program?

 pub fn sending_ping(addr: Addr<MicroscopeClient>) -> Result<(), ()> {
    info!("Pings started");

    spawn(async move {
        loop {
            info!("Ping");
            match addr.send(Ping {}).await {
                Ok(_) => {
                    info!("Ping sended")
                }
                Err(e) => {
                    warn!("Ping error");
                    return;
                }
            }
            std::thread::sleep(Duration::from_millis((4000) as u64));
        }
    });
    return Ok(());
}
jh316
  • 901
  • 7
  • 9
maks vell
  • 1
  • 2
  • 1
    Hi Maks, your question is not clear; what do you want it to do? – Ahmed Masud Jun 26 '22 at 16:41
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. – Community Jun 27 '22 at 05:56

2 Answers2

0

Assuming you are using tokio, calling tokio::spawn does not necessarily guarantee that the task will be executed on a separate thread (though it may be).

The problem here is that std::thread::sleep() completely blocks the thread that the task is running on, meaning your pings will run asynchronously (not blocking other tasks) but when you move on to the sleep nothing else on the current thread will execute for the next 4 seconds.

You can resolve this by using a non-blocking version of sleep, such as the one provided by tokio https://docs.rs/tokio/latest/tokio/time/fn.sleep.html

Thus your code would look like


 pub fn sending_ping(addr: Addr<MicroscopeClient>) -> Result<(), ()> {
    info!("Pings started");

    spawn(async move {
        loop {
            info!("Ping");
            match addr.send(Ping {}).await {
                Ok(_) => {
                    info!("Ping sended")
                }
                Err(e) => {
                    warn!("Ping error");
                    return;
                }
            }
            tokio::time::sleep(Duration::from_millis(4000)).await;
        }
    });
    return Ok(());
}

If you truly want to ensure that the task spawns on a different thread you would have to use std::thread::spawn but you would then have to set up another async runtime. Instead you could use spawn_blocking which at least guarantees the task is run on a thread where tasks are expected to block


0

I solved this particular problem in the following way

fn send_heartbeat(&self, ctx: &mut <Self as Actor>::Context) {
    ctx.run_interval(HEARTBEAT_INTERVAL, |act, ctx| {
        if Instant::now().duration_since(act.hb) > CLIENT_TIMEOUT {
            info!("Websocket Client heartbeat failed, disconnecting!");
            act.server_addr.do_send(Disconnect {
                id: act.user_id.clone(),
            });
            ctx.stop();

            return;
        }
    });
}

But I still don't know how to start some long process in a websocket in a separate thread, so that it does not block the websocket, with tokio="0.2.0" and actix="0.3.0".

maks vell
  • 1
  • 2