Files
vercel__next.js/test/e2e/app-dir/app-custom-cache-handler-errors/throwing-cache-handler.js
Sebastian "Sebbie" Silbermann ce207309be [test] Add coverage for throwing custom "use cache" cache handler (#95984)
This is relevant if the cache is in a broken state or the keys or
entries are not suitable (e.g. an entry that's to large to be stored).

Revealed several oddities:
1. cache handler have no no sources content (not too bad since that
means the codeframe points into the problem `use cache` function which
is usually the cause)
2. A throwing `set` is swallowed in dev
3. A throwing `get` is logged as a caught error and an unhandled
rejection. This is spammy.
2026-07-21 10:23:54 +02:00

80 lines
1.8 KiB
JavaScript

// @ts-check
/**
* A self-contained "use cache" cache handler that throws from the method
* specified via the `CACHE_HANDLER_THROW_ON` env var ('get' or 'set'). The
* other methods behave like a normal in-memory cache so that the throwing
* method is actually reached.
*/
/**
* @typedef {import('next/dist/server/lib/cache-handlers/types').CacheEntry} CacheEntry
* @typedef {Omit<CacheEntry, 'value'> & { chunks: Uint8Array[] }} StoredEntry
*/
/** @type {Map<string, StoredEntry>} */
const cache = new Map()
/**
* @type {import('next/dist/server/lib/cache-handlers/types').CacheHandler}
*/
const cacheHandler = {
async get(cacheKey) {
if (process.env.CACHE_HANDLER_THROW_ON === 'get') {
throw new Error('CustomCacheHandler.get failed')
}
const storedEntry = cache.get(cacheKey)
if (storedEntry === undefined) {
return undefined
}
const { chunks, ...entry } = storedEntry
return {
...entry,
value: new ReadableStream({
start(controller) {
for (const chunk of chunks) {
controller.enqueue(chunk)
}
controller.close()
},
}),
}
},
async set(cacheKey, pendingEntry) {
if (process.env.CACHE_HANDLER_THROW_ON === 'set') {
throw new Error('CustomCacheHandler.set failed')
}
const { value, ...entry } = await pendingEntry
/** @type {Uint8Array[]} */
const chunks = []
const reader = value.getReader()
while (true) {
const { done, value: chunk } = await reader.read()
if (done) {
break
}
chunks.push(chunk)
}
cache.set(cacheKey, { ...entry, chunks })
},
async refreshTags() {},
async getExpiration() {
return Infinity
},
async updateTags() {},
}
module.exports = cacheHandler