Repository navigation
fix(cache): keep each cache resolve inside its own request - #549
Conversation
workerd ties I/O to the request that started it. Nitro's cache and the shared cached() helper each kept one in-flight promise per key for the whole isolate. When the request that started a resolve answered first, workerd dropped its I/O and the promise never settled. Every later request on that key in the isolate then waited for it forever. Local workerd showed it: B and C hung past 45 s after A answered at 300 ms. Nitro now keeps in-flight resolves per H3 event through a pnpm patch. The shared helper drops its isolate-wide promise map. A stale key keeps one refresh per isolate through a 30 second claim, a finished value that lapses when its request ends.
|
Agent note from Harlan Agent Kit: checked by hand in local workerd, since CI cannot cover it. Setup:
The upstream log showed workerd closing A's fetch right after A answered. One case stays open. A |
🔗 Linked issue
Related to #540
❓ Type of change
📚 Description
Every cached route had the bug that #540 fixed for App mints. Nitro's
defineCachedFunctionkeeps one in-flight promise per key for the whole isolate, andsingleFlightinshared/server/cache.tsdid the same. The workerd runtime ties I/O to the request that started it. If that request answers before its resolve finishes, workerd drops the I/O and the promise never settles. Every later read of that key in the isolate then waits on it forever.What changes:
patches/nitropack@2.13.4.patchkeeps Nitro's in-flight resolves per H3 event. Reads inside one request still share one resolve. A call without an event resolves alone. This covers 14defineCachedEventHandlerroutes, the tag profiledefineCachedFunction, andllms.txtfromnuxt-ai-ready.shared/server/cache.tsdrops its isolate-wide promise map. A cold or dead key computes in each request that reads it. This covers 12cached()andreadThroughCache()call sites.readThroughCachenow serves the stale value while another request recomputes it. Before, it waited for that recompute.What this costs: