How to debounce inside actix's message handler?

Background

I am using actix and actix-web-actors to implement a websocket application. In server, a session will respond to message A sent from manager to send text to client. So I have the following code:

impl Handler<A> for Session {
    type Result = ();
    fn handle(&mut self, msg: A, ctx: &mut ws::WebsocketContext<Self>) {
        ctx.text(/* some text */)
    }
}

However, manager may send a lot of message A in a short time, so it is wise to "debounce" (if I pick the right word) inside this handler to minimize net communication, i.e., if there are multiple message A sent within a certain time (let's say 1 second), only the last message will be sent (and each new message will update the timer to re-count the time).

Question

I think inside async environment, it may be easier to implement such functionality (but I can't find any popular libraries in crates.io which provide such functionality). But actix's message handler is in a sync environment, which may be harder to "debounce".

I wonder whether it is necessary to use multi-thread to implement this feature, which is very heavy-weight and make a simple thing much more complicated, or there is a simple way or crate I can use to handle this thing?

I don't know if it is exactly what you need, but I have this piece of code laying around:

use std::sync::{Arc, Mutex};
use tokio::time::{Duration, Instant};

#[derive(Clone)]
pub struct Debouncer {
    inner: Arc<Mutex<DebouncerInner>>,
}

struct DebouncerInner {
    deadline: Instant,
    duration: Duration,
}

impl Debouncer {
    pub fn new(duration: Duration) -> Self {
        Self {
            inner: Arc::new(Mutex::new(DebouncerInner {
                deadline: Instant::now() + duration,
                duration,
            })),
        }
    }

    /// Reset the deadline, increasing the duration of any calls to `sleep`.
    pub fn reset_deadline(&self) {
        let mut lock = self.inner.lock().unwrap();
        lock.deadline = Instant::now() + lock.duration;
    }

    /// Sleep until the deadline elapses.
    pub async fn sleep(&self) {
        // This uses a loop in case the deadline has been reset since the
        // sleep started, in which case the code will sleep again.
        loop {
            let deadline = self.get_deadline();
            if deadline <= Instant::now() {
                // The deadline has already elapsed. Just return.
                return;
            }
            tokio::time::sleep_until(deadline).await;
        }
    }

    fn get_deadline(&self) -> Instant {
        let lock = self.inner.lock().unwrap();
        lock.deadline
    }
}

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.