Requests that missed the same variant at once each fetched and transcoded it (#65). A miss now goes through a singleflight.Group from golang.org/x/sync, keyed on CacheKey, which includes quality and fit.
The first request runs the existing path (cached source or fetch, transcode, store) unchanged, taking the upstream connection and processing slot as before. The others wait for its image or error, holding no slot and no source bytes, each with its own reader over the shared bytes.
Context: the shared work uses context.WithoutCancel of the first request's context, so the others are still served when that client leaves; upstream_fetch_timeout and the two 10-second waits still bound it. A waiting request returns as soon as its own context ends (DoChan with a select).
Counting: every request counts one miss, waiters included; the shared work counts its upstream fetch and transcode once each.
Every waiter gets the shared error; the next request starts afresh or is answered from the negative cache.
A panic in the shared work becomes an error; singleflight would re-raise it outside the router's recoverer and stop pixad.
Judgement call: the request running the work waits for it even when its own context ends, as on next; letting it leave like the others would change TestService_Get_CountsInterruptedMisses, which needs the owner's approval.
Judgement call: a request whose context has already ended starts no work.
Disclosure: IncrementStats keeps its fetchBytes parameter, now always 0 from Get, as existing tests pass it bytes.
Disclosure: a request that misses just as another's work finishes may transcode again; its source is cached by then.
Model: opus-5-5
Requests that missed the same variant at once each fetched and transcoded it (https://git.eeqj.de/sneak/pixa/issues/65). A miss now goes through a `singleflight.Group` from `golang.org/x/sync`, keyed on `CacheKey`, which includes quality and fit.
- The first request runs the existing path (cached source or fetch, transcode, store) unchanged, taking the upstream connection and processing slot as before. The others wait for its image or error, holding no slot and no source bytes, each with its own reader over the shared bytes.
- Context: the shared work uses `context.WithoutCancel` of the first request's context, so the others are still served when that client leaves; `upstream_fetch_timeout` and the two 10-second waits still bound it. A waiting request returns as soon as its own context ends (`DoChan` with a `select`).
- Counting: every request counts one miss, waiters included; the shared work counts its upstream fetch and transcode once each.
- Every waiter gets the shared error; the next request starts afresh or is answered from the negative cache.
- A panic in the shared work becomes an error; singleflight would re-raise it outside the router's recoverer and stop pixad.
Judgement call: the request running the work waits for it even when its own context ends, as on `next`; letting it leave like the others would change `TestService_Get_CountsInterruptedMisses`, which needs the owner's approval.
Judgement call: a request whose context has already ended starts no work.
Disclosure: `IncrementStats` keeps its `fetchBytes` parameter, now always 0 from `Get`, as existing tests pass it bytes.
Disclosure: a request that misses just as another's work finishes may transcode again; its source is cached by then.
Model: opus-5-5
Requests that miss the same variant while its fetch is held must make
one fetch and one transcode between them, all get the same image and
each count one miss. Variants differing only in quality or fit stay
apart. A waiting request whose context ends returns at once; the first
request's client leaving does not stop the work. A shared failure
reaches every request, the negative cache answers the next one, and an
uncached failure is fetched again. A request that has already ended
fetches nothing, and a panic comes back as an error. All but the
variants test fail on next.
Model: opus-5-5
Requests that missed the same variant at once each fetched and
transcoded it. They now share one call through
golang.org/x/sync/singleflight, keyed on the variant cache key. The
first request processes the variant with a context that does not end
with its own; the others wait for its result, holding no connection or
processing slot, and return as soon as their own context ends. The
processing request waits even then, as before. Each request counts one
miss; the processing counts its fetch and transcode once. A panic
while processing becomes an error instead of stopping pixad.
Model: opus-5-5
Rebased onto the current next. Only TODO.md conflicted; I kept both Completed Steps entries, with this one on top.
internal/imgcache/cache.go and internal/imgcache/service.go merged without a conflict and needed no change. The shared processing calls StoreVariant once, which fills the in-memory content types from #70. Any later request for that variant is a cache hit and gets its type from memory through GetVariant.
Judgement call: requests that wait on the shared processing still get its image directly, as before, rather than reading it back from the cache.
Model: opus-5-5
Rebased onto the current `next`. Only `TODO.md` conflicted; I kept both Completed Steps entries, with this one on top.
`internal/imgcache/cache.go` and `internal/imgcache/service.go` merged without a conflict and needed no change. The shared processing calls `StoreVariant` once, which fills the in-memory content types from https://git.eeqj.de/sneak/pixa/issues/70. Any later request for that variant is a cache hit and gets its type from memory through `GetVariant`.
Judgement call: requests that wait on the shared processing still get its image directly, as before, rather than reading it back from the cache.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Requests that missed the same variant at once each fetched and transcoded it (#65). A miss now goes through a
singleflight.Groupfromgolang.org/x/sync, keyed onCacheKey, which includes quality and fit.context.WithoutCancelof the first request's context, so the others are still served when that client leaves;upstream_fetch_timeoutand the two 10-second waits still bound it. A waiting request returns as soon as its own context ends (DoChanwith aselect).Judgement call: the request running the work waits for it even when its own context ends, as on
next; letting it leave like the others would changeTestService_Get_CountsInterruptedMisses, which needs the owner's approval.Judgement call: a request whose context has already ended starts no work.
Disclosure:
IncrementStatskeeps itsfetchBytesparameter, now always 0 fromGet, as existing tests pass it bytes.Disclosure: a request that misses just as another's work finishes may transcode again; its source is cached by then.
Model: opus-5-5
aead642746to4009490242Rebased onto the current
next. OnlyTODO.mdconflicted; I kept both Completed Steps entries, with this one on top.internal/imgcache/cache.goandinternal/imgcache/service.gomerged without a conflict and needed no change. The shared processing callsStoreVariantonce, which fills the in-memory content types from #70. Any later request for that variant is a cache hit and gets its type from memory throughGetVariant.Judgement call: requests that wait on the shared processing still get its image directly, as before, rather than reading it back from the cache.
Model: opus-5-5
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.