# Scheduler Lifecycle

This page shows how each scheduler operation behaves before `Start` and while the event loop is running.

## Operations by State

| Operation | Not started | Running |
|---|---|---|
| `Add` | Appended to the heap directly | Sent to the event loop via the `add` channel |
| `Remove` | Disabled and removed from the heap | Removed via the `remove` channel |
| `RemoveAll` | Disables every task | Clears the heap via the `removeAll` channel |
| `Start` | Starts the worker pool and event loop | No-op |
| `Stop` | Returns an immediately cancelled context | Stops the loop, waits for workers, returns a context cancelled after in-flight tasks finish |

## Restarting After Stop

`Start` after `Stop` restarts the event loop, so tasks without dependencies fire again. The dependency workers do not come back: `Stop` closes the workers' stop channel and `Start` reuses it, so each new worker exits immediately. Dependent tasks are then queued on trigger but never evaluated, and once the 1024-slot wait queue is full the event loop blocks. A second `Stop` after such a restart closes the same channel again and panics with `close of closed channel`. Create a new scheduler with `core.New` instead of restarting one that has dependent tasks.

See [Scheduler API](/api-reference) for `New`, `Start`, and `Stop` signatures.
