Skip to content

Bug: Zombie task created when fast-completing task races the map insert #18

Description

@ZialeHub

Description

In both async_scheduler.rs and sync_scheduler.rs, the worker task/thread is spawned before the entry is inserted into the map. If the task completes quickly (e.g. count(1)), it executes its
self-removal (tasks.write().remove(&id)) on a key that doesn't exist yet — the remove is a no-op. Then schedule() inserts the entry at line 108. The result is a permanent zombie entry in the map that never
gets cleaned up.

Affected files

  • src/scheduler/async_scheduler.rs — line 50 (spawn) vs line 108 (insert)
  • src/scheduler/sync_scheduler.rs — line 50 (spawn) vs line 108 (insert)

Reproduction

let mut scheduler = Scheduler::build();
let task = MyTask::new();
// count(1) with a very short interval — task completes before insert
scheduler.schedule(Box::new(task.clone()), every(1.seconds()).count(1)).unwrap();

// Later — same task can never be scheduled again:
let result = scheduler.schedule(Box::new(task), every(1.seconds()).count(1));
assert!(matches!(result, Err(PulsyncError::AlreadyScheduled(_)))); // stuck forever                                                                                                              

Impact

- The TaskId is permanently stuck in the scheduler map.
- All future schedule() calls for the same task parameters return Err(AlreadyScheduled) indefinitely.
- Memory is leaked (the AsyncTask/SyncTask entry is never freed).

Fix

Insert the entry into the map before spawning the worker. The spawned closure already holds a clone of the Arc, so inserting first is safe:

// 1. Insert first
self.write().unwrap().insert(id, task_entry);
// 2. Then spawn
let handle = tokio::spawn(async move { ... });
// 3. Update the handle in the map after spawn
self.write().unwrap().get_mut(&id).unwrap().handle = handle;

Or restructure the AsyncTask/SyncTask to accept the handle as a separate step via an Option<JoinHandle>.

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