Definition
A generation guard in async HTTP caches such as Service Workers increments a generation number on invalidation (deletion), and each network revalidate request remembers the generation at start and checks it is still the same before storing, so stale responses that finish after deletion are not written back to cache.
Why it matters
service-worker-stale-while-revalidate returns cache immediately on hit and continues fetch in the background. Even after the user deletes cache, a fetch started before deletion can complete later and cache.put can revive the deleted original.
For performance, "old image for a moment" may be tolerable, but after PII masking or logout, showing the original again is a security incident. A lightweight integer generation judges store eligibility instead of a mutex.
How it works
- SW global:
let generation = 0. clearCachemessage:generation++→ delete body and meta from Cache Storage → ACK to page.- Revalidate start:
const captured = generation. - After
fetchcompletes:if (captured !== generation) return— skip store. - Page: masking API success →
await clearImageCache()(including ACK) → then update client state and image URL. - Same clear path on session end such as logout.
Page helper when SW is missing or unresponsive:
- Run
caches.deletedirectly from the page, - Send SW
postMessagedelete in parallel, and - Cap ACK wait (e.g. 1.5s max) so UI does not hang.
Practical application
For sensitive data, deletion complete is a precondition for UI update. On failure, not showing the previous original as fallback is safer.
Trade-offs
- Generation lives only in SW instance memory — resets to 0 on SW restart, but cache is often cleared on restart too, which is acceptable in practice.
- ACK wait can add hundreds of ms to masking UX — accepted as a trade-off at security boundaries.
- Global generation suits full image cache clear. For frequent partial invalidation, consider per-key generation or version fields.
When not to use
- Simple static assets (version-hashed filenames) often need no generation because the filename itself invalidates.
- If only the server is authoritative and the client does not cache, SW generation is unnecessary.
- Incrementing generation without actual
deletemakes the guard meaningless.
Common mistakes
- Changing UI URL right after
cache.delete(key)without ACK and generation. - Showing cached original first via SWR right after masking.
- Leaving cache on logout so the next user sees previous session images.
- Infinite MessageChannel ACK wait — no timeout or direct-delete fallback.
Related concepts
- service-worker-stale-while-revalidate — background revalidate creates the race
- presigned-url-cache-key-normalization — separate axis from key collision
- race-safe-async-ui-requests — async ordering and cancellation on the UI side