Description
UniqueId::unique_id() hashes only recurrence + self.salt() using std::hash::DefaultHasher. The default implementation of Salt::salt() returns an empty string. This means any two different task types that both
use the default salt and are scheduled with the same Recurrence will produce the same TaskId, causing the second schedule() call to silently return Err(AlreadyScheduled) even though the two tasks are entirely
different.
Additionally, DefaultHasher is explicitly documented by Rust as not guaranteed to be stable across Rust versions, which breaks the serde restart() feature.
Affected file
- src/task/mod.rs — unique_id() method (lines 69–75)
Reproduction
#[derive(Task, Salt)] struct TaskA { val: TaskState<u32> }
impl SyncTaskHandler for TaskA { fn run(&self) {} }
#[derive(Task, Salt)] struct TaskB { val: TaskState<u32> }
impl SyncTaskHandler for TaskB { fn run(&self) {} }
let rec = every(5.seconds());
scheduler.schedule(Box::new(TaskA::new(0)), rec).unwrap(); // Ok
scheduler.schedule(Box::new(TaskB::new(0)), rec).unwrap(); // Err(AlreadyScheduled) — wrong!
Fix
Mix the concrete type identity into the hash to guarantee uniqueness across types:
fn unique_id(&self, recurrence: Recurrence) -> TaskId {
let mut hasher = DefaultHasher::new();
recurrence.hash(&mut hasher);
std::any::TypeId::of::<Self>().hash(&mut hasher);
self.salt().hash(&mut hasher);
hasher.finish()
}
Also consider replacing DefaultHasher with a stable, deterministic hasher (e.g. FxHasher or a fixed-seed SipHash) to protect the serde restart feature against cross-version breakage.
Description
UniqueId::unique_id() hashes only recurrence + self.salt() using std::hash::DefaultHasher. The default implementation of Salt::salt() returns an empty string. This means any two different task types that both
use the default salt and are scheduled with the same Recurrence will produce the same TaskId, causing the second schedule() call to silently return Err(AlreadyScheduled) even though the two tasks are entirely
different.
Additionally, DefaultHasher is explicitly documented by Rust as not guaranteed to be stable across Rust versions, which breaks the serde restart() feature.
Affected file
Reproduction
Fix
Mix the concrete type identity into the hash to guarantee uniqueness across types:
Also consider replacing DefaultHasher with a stable, deterministic hasher (e.g. FxHasher or a fixed-seed SipHash) to protect the serde restart feature against cross-version breakage.