Design a graceful worker pool in Go
concurrency coordination with goroutines, channels, and context.
buffered job channel, fixed worker goroutines, WaitGroup to await in-flight work, context cancellation to stop intake.
WHAT THIS TESTS This probes whether you can compose Go's core concurrency primitives correctly: goroutines, channels, sync.WaitGroup, and context. Interviewers want to see that you understand ownership of channels, who closes them, and how cancellation propagates without leaking goroutines or panicking on a closed channel.
A GOOD ANSWER COVERS A pool struct holds a jobs channel and a WaitGroup. Start spawns a fixed N goroutines, each ranging over the jobs channel so they exit naturally when it is closed. Submit sends onto the jobs channel but uses a select against ctx.Done so it returns an error instead of blocking after shutdown begins. Shutdown is triggered by cancelling the context; the owner then closes the jobs channel exactly once, which ends every worker's range loop. The WaitGroup, incremented by Add(N) before launching workers and decremented with deferred Done, lets Wait block until all in-flight jobs finish. Only after Wait returns is the pool fully drained.
COMMON WRONG ANSWERS Closing the jobs channel from inside a worker or from a sender, which causes a send-on-closed-channel panic. Forgetting deferred Done, so Wait hangs forever. Using an unbuffered channel and claiming it gives concurrency. Spawning a new goroutine per job, defeating the fixed-pool requirement. Relying on time.Sleep to wait for completion.
LIKELY FOLLOW-UPS How do you collect results and errors? Add a results channel and a separate consumer. How do you bound memory? Use a buffered jobs channel as backpressure. How do you make the pool generic? Use type parameters so jobs and results carry typed payloads. What about per-job timeouts versus pool-wide cancellation?
ONE CONCRETE EXAMPLE Imagine a thumbnail service processing image jobs. Eight workers range over a jobs channel. A SIGTERM cancels the root context; Submit immediately rejects new uploads, the channel is closed, and the eight workers finish the images already pulled. WaitGroup.Wait returns once the last thumbnail is written, and the process exits cleanly with no half-written files or orphaned goroutines.
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.