No request coalescing: K concurrent misses for the same variant cause K upstream fetches and K transcodes #65
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Verified against
mainat61f42e6.Service.Get(internal/imgcache/service.go:103-158) has no singleflight or equivalent. K simultaneous requests for the same uncached variant each miss the cache, each fetch the source from the upstream, and each run a full libvips transcode, before K identical results race to write the same cache entry.This is the classic thundering herd, and it is the worst case for exactly the traffic pattern an image CDN sees: a popular image going cold, or a cache-cleared restart under live traffic. It multiplies both the upstream load we impose on origins and our own CPU/memory use, and it directly contradicts the 1-5k req/s target in
README.md:49.It also interacts badly with the concurrency cap filed separately: without coalescing, the cap gets consumed by duplicate work.
Definition of done
golang.org/x/sync/singleflightrather than hand-rolling (per the stdlib/well-maintained-library preference —golang.org/x/syncis already the closest thing to stdlib here; confirm it against~/.claude/GO_PACKAGE_DEFAULTS.mdbefore adding, and add the decision there if absent).internal/imgcache/cache.go:214) still behaves.Getcalls for the same uncached key result in exactly one fetch against a counting mock fetcher (internal/httpfetcher.MockFetcheralready exists), and all N callers get correct bytes.make checkgreen (suite runs with-raceas of #55).Related
Service.Getand both target the same blowup.