rusttimercallbacktimeout

Rust timer not triggering after the specified timeout


I am having some problems with timers: I cannot identify the reason why this is not working properly:

use std::sync::{Arc, Mutex};

use timer::Timer;

struct Counter {
    value: i32,
}

impl Counter {
    fn new() -> Self {
        Self { value: 0 }
    }

    fn increment(&mut self) {
        self.value += 1;
    }

    fn get_value(&self) -> i32 {
        self.value
    }
}

#[test]
fn test_1() {
    let counter = Arc::new(Mutex::new(Counter::new()));
    let counter_clone_1 = Arc::clone(&counter);
    let counter_clone_2 = Arc::clone(&counter_clone_1);

    // Arrange
    let callback = {
        move || {
            println!("Callback executed");
            counter_clone_1.lock().unwrap().increment();
        }
    };

    let timer = Timer::new();
    println!("Timer created");
    timer.schedule_with_delay(chrono::Duration::seconds(2), callback);

    // Assert initial value
    println!("Initial assert");
    assert_eq!(counter_clone_2.lock().unwrap().get_value(), 0);

    // Act
    println!("Sleeping for 4 seconds");
    std::thread::sleep(std::time::Duration::new(4, 0));

    // Assert incremented value
    println!("Final assert");
    assert_eq!(counter.lock().unwrap().get_value(), 1);
}

Why is the callback not being called after the specified timeout?

I tried with multiple timeouts (including zero) without success and this is the outcome I see:

Timer created
Initial assert
Sleeping for 4 seconds
Final assert
thread 'missed_ping_timer_tests::test_1' panicked at tests\missed_ping_timer_tests.rs:51:5:
assertion `left == right` failed
  left: 0
 right: 1

This is what I have in my Cargo.toml file:

[dependencies]
timer = "0.2.0"
chrono = "0.4.39" 

Solution

  • If you read the documentation of schedule_with_delay you'll find it says:

    This method returns a Guard object. If that Guard is dropped, execution is cancelled.

    Since you don't assign the guard object to any variable it is immediately dropped and execution of the callback is cancelled.

    You can simply assign it to a binding to not drop and cancel it immediately:

    let _guard = timer.schedule_with_delay(chrono::Duration::seconds(2), callback);
    

    The leading underscore suppresses the warning that the variable is not used