Ch 10: Scheduling and Parallel Dispatch
Imagine you are standing in the control tower of a busy airport. Through the glass, you see four runways stretching out in front of you. Planes are circling overhead, each one a task waiting to land.
Flight 1 is carrying the implementation code. Flight 2 has the test suite. Flight 3 has the linter results. Flight 4 has the documentation update.
Here is the problem: Flight 2 (tests) cannot land until Flight 1 (implementation) has landed and taxied off the runway. You cannot test code that does not exist yet. Flight 3 (lint) also needs Flight 1 to land first. But Flights 2 and 3 do not depend on each other — they can land at the same time on different runways.
Flight 4 (docs) is waiting for both Flight 2 and Flight 3. It needs the tested, linted code before it can document the final API.
Your job as the air traffic controller is to look at all the dependencies, figure out which planes can land in parallel, and dispatch them to runways as efficiently as possible — without ever letting two dependent planes collide.
This is exactly what a scheduler does in a multi-agent system. Tasks are planes. Dependencies are landing priorities. Runways are worker slots. And you — the scheduler — manage the airspace.
Sequential vs Parallel Execution
The naive approach is sequential: land one plane at a time. Flight 1, then Flight 2, then Flight 3, then Flight 4. Safe, simple, slow. If each task takes 10 minutes, you finish in 40 minutes.
But look at the dependencies again. After Flight 1 lands, Flights 2 and 3 are both ready. They do not depend on each other. If you dispatch them to separate runways at the same time, they run in parallel. Now the total time drops to 30 minutes — or less if the parallel tasks are fast.
This is dependency-aware scheduling. The scheduler does not just run tasks in a fixed order. It builds a map of what depends on what — a directed acyclic graph (DAG) — and uses it to find the maximum parallelism at every step.
The algorithm is straightforward:
- Find all tasks with no unfinished dependencies — these are "ready"
- Dispatch all ready tasks in parallel
- When a task completes, check if it unblocked any new tasks
- Repeat until everything is done or something fails
The key insight: you never dispatch a task until all of its dependencies have completed. But you always dispatch as many independent tasks as possible at the same time.
You are the Scheduler. Four tasks just arrived. Let's figure out the dispatch order.
Put the scheduling steps in the correct order
Drag to reorder, or use Tab + Enter + Arrow keys.
- Analyze task dependencies
- Group independent tasks
- Dispatch parallel group
- Wait for all in group to complete
- Dispatch next sequential task
Key Insight
It is tempting to think parallelism is limited by resources — the number of runways, the number of workers, the API rate limit. And resources do matter. But the true ceiling on parallelism is the dependency graph.
If every task depends on the one before it — a straight chain — then no amount of extra runways will help. You are stuck running sequentially. But if the graph is wide, with many independent branches, you can dispatch dozens of tasks at once.
The scheduler's job is to find the width of the graph at each level and exploit it. Resources set the floor. Dependencies set the ceiling. A good scheduler pushes actual parallelism as close to that ceiling as the resources allow.
This is why modeling dependencies explicitly matters. Without a DAG, you either run everything sequentially (too slow) or everything in parallel (tasks crash because inputs are not ready). The scheduler walks the line between speed and correctness — just like a real air traffic controller.
What's Next
You have a scheduler that can run tasks in dependency order with controlled parallelism. But the scheduler auto-executes everything. Some tasks — modifying production configs, deleting files, deploying to staging — need human review before they proceed.
In Chapter 11, you will build a review queue that gates critical tasks behind human approval. The scheduler dispatches the task, but instead of auto-executing, it parks the task in a review queue and waits for a human decision.