Go Module 15
Concurrency patterns in Go interview questions
Interview questions on concurrency patterns in Go: short warm-ups, then what each harder question tests, the first step of a good answer and its follow-ups.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher
In a pipeline, which goroutine closes a channel, and why that one?
-
Fresher to mid
How does a buffered channel of struct{} work as a semaphore, and where do you take the slot?
Answered in the lesson Worker pools, semaphores and bounded parallelism
-
Fresher to mid
What is a goroutine leak, and why does the Go runtime not report it as a deadlock?
Answered in the lesson Goroutine leaks and the goroutineleak profile
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Mid to senior
A handler streams records through a three-stage pipeline and returns at the first invalid record. Since that change shipped, the service's goroutine count climbs by about three for every failed request. Explain why, and change the pipeline so that it cannot happen.
- What it tests
- Recognising senders left blocked after an early return, and stopping every stage through a context instead of relying on buffers.
- First step
- Count the stages: when the handler stops reading, each stage that holds a value waits in its send for ever, one goroutine per stage, which matches three per failed request. Then decide how every stage can learn that nobody reads any more.
- Follow-ups
-
- Would giving every channel a buffer fix it?
- How would you prove the fix in a test?
- What if a stage is blocked in a call that ignores the context?
From the lesson Pipelines, fan-out and fan-in
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to staff
An enrichment stage was fanned out to 16 workers to cut latency, and now the downstream report comes out in a different order on every run. Restore the input order without giving up the speed-up. How much memory can your fix hold at worst?
- What it tests
- Carrying an index through a fan-out, reordering with a buffer that is bounded, and reasoning about a slow item that holds back everything after it.
- First step
- Tag each item with its position before the fan-out, and let a reorder stage send item n only after items 0 to n-1. Then ask what limits the number of items it holds while one slow item is still being worked on.
- Follow-ups
-
- What happens to latency and memory when one item takes 10 seconds?
- Why not collect everything and sort at the end?
- How do you put a hard bound on the reorder buffer?
From the lesson Pipelines, fan-out and fan-in
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
An upload service starts one goroutine per uploaded photo, and each goroutine calls an image API that accepts at most 20 requests at once. A marketing email brings 5,000 uploads in a minute, and most of them fail. Explain why, and redesign the service.
- What it tests
- Seeing that unbounded goroutines move the limit downstream, and choosing a bound, a queue and an answer for the work that cannot be queued.
- First step
- Compare the number of calls the burst puts in flight with the 20 the API accepts: thousands of goroutines call at once, so the API refuses nearly all of them. Then decide where the waiting should happen instead, and what a user hears when there is no room to wait.
- Follow-ups
-
- How big should the queue in front of the workers be?
- Should a full queue make the upload wait or fail?
- What changes when the image API slows from 200 ms to 2 seconds?
From the lesson Worker pools, semaphores and bounded parallelism
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
A Go service must make 1,500 calls a second to a payments API whose median latency is 80 ms and whose p99 is 400 ms. How many workers do you give the pool, and what happens to that choice when the API's latency doubles during an incident?
- What it tests
- Turning a rate and a latency into the number of calls in flight, choosing which latency to size for, and knowing what a fixed pool does to throughput when latency rises.
- First step
- Start from the rate and from how long each call keeps a worker busy, and work out how many calls are in flight at once on average. Then ask which latency that average needs, the median or something higher, and whether the payments API itself accepts that many calls at once.
- Follow-ups
-
- Why is sizing for the p99 wasteful, and sizing for the median risky?
- What does the pool do to throughput when latency doubles?
- How would you size a pool for a CPU-heavy step of the same service?
From the lesson Worker pools, semaphores and bounded parallelism
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
On every deploy, a service with an HTTP server and a worker pool loses some queued jobs, and once in a while it panics with "send on closed channel". Walk through a shutdown that loses nothing, and say what you do when the deadline is too short to drain the queue.
- What it tests
- Finding why a send on a closed channel happens at shutdown, stopping the parts of a service in a safe order, and accounting for the jobs that cannot run before the deadline.
- First step
- Find who closes the jobs channel and when. The panic means a handler sent on the queue after it was closed, so the queue was closed while requests were still being served. Then trace what happens to the jobs still queued when the process exits.
- Follow-ups
-
- Why does closing the queue from the signal handler cause the panic?
- How do you drain with a deadline, and what do you do with the jobs left over?
- How would you test the shutdown without waiting real seconds?
From the lesson Worker pools, semaphores and bounded parallelism
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A Go service's memory climbs steadily between deploys and drops after each restart, and runtime.NumGoroutine climbs the same way. How do you find the leak, and what do you look for in the code once you know where the goroutines wait?
- What it tests
- Telling a goroutine leak from other memory growth, using the goroutineleak and goroutine profiles to find where goroutines wait, and recognising the code shapes that cause it.
- First step
- Confirm that the goroutine count, not only memory, grows with time or with failed requests. Then take the goroutineleak profile from the service's internal pprof endpoint and read where the leaked goroutines wait: the function and line point at the channel whose other side is gone.
- Follow-ups
-
- How do you link the growth to a kind of request?
- The profile points at a send inside a closure. What do you look for around it?
- How do you stop the same leak from coming back?
From the lesson Goroutine leaks and the goroutineleak profile
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
runtime.NumGoroutine rises by thousands a day, but the goroutineleak profile reports total 0. Which kinds of leak can hide from the profile, and how do you find this one?
- What it tests
- Knowing how the profile decides that a goroutine has leaked, which leaks that rule cannot see, and how to find them with other tools.
- First step
- Recall what the profile can know: whether anything that can still run could wake a blocked goroutine. Then ask what kinds of goroutine never return without being blocked on something unreachable, and which other profile shows every goroutine with its stack.
- Follow-ups
-
- Why can a goroutine waiting on a global channel never be reported?
- How do you find a loop that never ends in a profile of all goroutines?
- What would you change in the code so the profile can help next time?
From the lesson Goroutine leaks and the goroutineleak profile
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
After goleak.VerifyNone was added to every test of a package, its tests fail in different places depending on which tests run, and some tests of correct code fail. Explain what happens, and set up leak checks whose failures point at the test that leaked.
- What it tests
- Understanding what goleak checks and when, and arranging leak checks so that each failure names the test that caused it.
- First step
- Ask how long a leaked goroutine lives and what goleak can know about where a goroutine came from. Then look at which tests fail first when the package's tests run in a different order.
- Follow-ups
-
- Why does running one test alone pass?
- When is VerifyTestMain the better choice?
- A library starts a background goroutine on purpose. How do you keep the check?
From the lesson Goroutine leaks and the goroutineleak profile
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
A deploy empties the cache, then 5,000 requests a second hit product pages whose entries are all cold, and the database falls over. Explain the stampede, fix it in Go, and say what the waiting requests get when a shared load fails.
- What it tests
- Recognising duplicate loads of one key, collapsing them per key, handling failed and slow shared loads, and keeping the cache and the collapsing apart.
- First step
- Count how many requests for each hot key miss the cache while its first load is still running: each one sends its own query. Then decide how the callers of one key can share one load, and what a shared failure means for them.
- Follow-ups
-
- What do the waiting requests get when the shared load fails?
- A load sometimes takes 3 seconds and requests have a 300 ms deadline. What changes?
- How do you warm the cache after a deploy without a stampede?
From the lesson Concurrent caches, singleflight and pub/sub
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
A Go broker sends price updates to 2,000 WebSocket subscribers, one channel send each, and a slow mobile client makes every update late for everyone. Explain why, and redesign delivery so that a slow client hurts only itself.
- What it tests
- Seeing that a blocking send to one subscriber delays all of them, choosing a slow-consumer policy from what clients need, and sizing buffers from rates.
- First step
- Look at what Publish does when one subscriber's channel is full: if it waits, every later subscriber and every later event waits with it. Then ask what a price subscriber needs, every update or only the latest.
- Follow-ups
-
- Which policy would you choose for prices, and which for chat messages?
- How big should each subscriber's buffer be?
- How does a disconnected client catch up?
From the lesson Concurrent caches, singleflight and pub/sub
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A cache calls an OnEvict callback while it holds its mutex, and under load the service sometimes freezes with no error and no panic. Explain the freeze and redesign the callback path.
- What it tests
- Recognising a goroutine waiting for a mutex it already holds and slow work under a lock, and moving callbacks out of the critical section safely.
- First step
- Ask what the callback may call: if it reaches back into the cache, or waits for anything that needs the cache's lock, it waits for itself. Then consider how the cache could run its callbacks after it has unlocked.
- Follow-ups
-
- Why is there no deadlock report from the runtime?
- How do you keep the callbacks in eviction order once they run outside the lock?
- How would you find this freeze in a running service?
From the lesson Concurrent caches, singleflight and pub/sub
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes