Skip to content

Bug: abort() on sync tasks does not interrupt the sleeping thread #20

Description

@ZialeHub

Description

The async scheduler correctly cancels the Tokio task immediately via task.handle.abort(). The sync scheduler has no equivalent — after abort() sets TaskStatus::Abort and removes the entry from the map, the
background std::thread continues sleeping in std::thread::sleep(duration) for the full recurrence interval before it notices the status change.

Affected file

  • src/scheduler/sync_scheduler.rs — abort() method (lines 186–193)

Reproduction

  // Sync feature enabled
  let mut scheduler = Scheduler::build();
  let id = scheduler.schedule(Box::new(task), every(3600.seconds())).unwrap();
  scheduler.abort(id).unwrap(); // returns Ok immediately
  // The background thread is now sleeping for ~1 hour despite abort() returning Ok

Impact

  • abort() silently lies: it returns Ok(()) but the task thread is still alive and consuming resources.
  • For long intervals, threads can leak for hours.
  • If the Scheduler is dropped after abort(), the orphaned threads keep the Arc clones alive, preventing memory from being freed.

Fix

Replace std::thread::sleep with a Condvar+Mutex based wait, or an std::sync::mpsc channel. The abort() method signals the condvar/channel to wake the thread immediately:

  // In the loop, replace sleep with:
  let timeout = condvar.wait_timeout(guard, duration).unwrap();
  if *status.read().unwrap() == TaskStatus::Abort { break; }

  // In abort():
  condvar.notify_one(); // wakes the thread immediately

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions