Description
reschedule() atomically writes a new Recurrence into the Arc<RwLock>. However, the scheduler loop reads the interval before calling sleep, and tokio::time::sleep / std::thread::sleep is not
cancellable from outside once started. The new interval is therefore silently ignored for the remainder of the current sleep and only takes effect on the next iteration.
Affected files
- src/scheduler/async_scheduler.rs — lines 90–95
- src/scheduler/sync_scheduler.rs — lines 90–95
Reproduction
let id = scheduler.schedule(Box::new(task), every(3600.seconds())).unwrap();
// 1 second later:
scheduler.reschedule(id, every(1.seconds())).unwrap();
// Task does not run for another ~3599 seconds — reschedule had no immediate effect
Impact
Users calling reschedule() reasonably expect the new interval to take effect promptly. This is especially confusing when shortening a long interval.
Fix
Async: Replace tokio::time::sleep with a tokio::sync::Notify or tokio::time::interval + reset so the sleep can be interrupted:
// Use a Notify stored alongside the task
notify.notify_one(); // called inside reschedule()
// In the loop:
tokio::select! {
_ = tokio::time::sleep(duration) => {}
_ = notify.notified() => {}
}
Sync: Use the same Condvar introduced for abort() interrupt (see issue).
Description
reschedule() atomically writes a new Recurrence into the Arc<RwLock>. However, the scheduler loop reads the interval before calling sleep, and tokio::time::sleep / std::thread::sleep is not
cancellable from outside once started. The new interval is therefore silently ignored for the remainder of the current sleep and only takes effect on the next iteration.
Affected files
Reproduction
Impact
Users calling reschedule() reasonably expect the new interval to take effect promptly. This is especially confusing when shortening a long interval.
Fix
Async: Replace tokio::time::sleep with a tokio::sync::Notify or tokio::time::interval + reset so the sleep can be interrupted:
Sync: Use the same Condvar introduced for abort() interrupt (see issue).