Problem
Many callers simultaneously ask for the same expensive resource, so the backend repeats identical work and is overloaded by duplicates. Caches do not help while the first computation is still in flight.
Also known as: single-flight, request-collapsing
Merge identical concurrent requests into one upstream call and share the result among all waiters.
Many callers simultaneously ask for the same expensive resource, so the backend repeats identical work and is overloaded by duplicates. Caches do not help while the first computation is still in flight.
Request coalescing, also called single-flight or request collapsing, ensures that only one execution of an identical operation runs at a time. It targets the window in which a cache cannot help yet: the moment between the first miss and the first stored result.
inflight = {}
func get(key):
if key in inflight: return inflight[key].wait()
call = start(loader, key)
inflight[key] = call
try: return call.wait()
finally: delete inflight[key]
Go's singleflight package implements this idea directly. CDNs and reverse proxies do the same with request collapsing: when 500 clients request an uncached object, one request goes to the origin and the other 499 wait for its response.
Choose the key carefully: normalize parameters and exclude per-request noise such as trace ids. Run the shared call with its own timeout, detached from any individual caller's context, so one impatient caller cannot cancel the work for the rest.
Coalescing works best with a cache. The shared result is stored, so later arrivals hit the cache instead of starting a new flight.
None
Low: add metrics for coalesced counts
Medium: concurrency and cancellation
Shared call hangs and every waiter hangs with it
Key that includes irrelevant fields prevents any coalescing
First caller cancels and aborts the call for everyone