Problem
A large job, such as querying many shards or processing many files, takes too long sequentially. Running pieces in parallel needs a way to track completion and merge outputs, including partial failures.
Also known as: scatter-gather, split and aggregate
Split a task into parallel subtasks distributed across workers, then collect and combine their results.
A large job, such as querying many shards or processing many files, takes too long sequentially. Running pieces in parallel needs a way to track completion and merge outputs, including partial failures.
Fan-out fan-in, also called scatter-gather, trades coordination complexity for speed. The job is split, processed concurrently and joined.
The hard part is not the fan-out; it is knowing when the fan-in is done and what to do when it never completes.
The aggregator needs thought. Counting arrivals is fragile under duplicate delivery, so record results by part index in durable storage and complete when all indices are present. Workflow engines can express this directly as parallel steps with a join, saving you from hand-building the tracking logic.
The coordinator publishes N subtasks with a job id. The aggregator persists a record per job and marks each part as it arrives.
job = new_id(); parts = split(input)
for i, p in enumerate(parts):
publish("work", {job, i, n: len(parts), p})
# aggregator
state[job].parts[i] = result # idempotent by index
if len(state[job].parts) == n or past_deadline(job):
emit(merge(state[job]))
Tail latency matters because the job finishes when the slowest part does. Mitigate with timeouts, hedged retries for stragglers and smaller chunks. Decide the partial-failure contract up front: fail the whole job, return partial results with a flag, or retry only missing parts. Cap concurrency so the fan-out does not overwhelm shared downstream resources.
Medium - queue, workers, aggregator state
Medium - job tracking
Medium - join semantics
One lost subtask leaves the job waiting forever
Duplicate result double counts in the aggregate
Aggregator crash loses in-memory progress