diff --git a/.changeset/lovely-gifts-cough.md b/.changeset/lovely-gifts-cough.md new file mode 100644 index 00000000..aaf33679 --- /dev/null +++ b/.changeset/lovely-gifts-cough.md @@ -0,0 +1,26 @@ +--- +"@opennextjs/cloudflare": minor +--- + +Add option for regional cache to skip tagCache on cache hits + +When the tag regional cache finds a value in the incremental cache, checking such value in the tagCache can be skipped, this helps reducing response times at the tradeoff that the user needs to either use the automatic cache purging or manually purge the cache when appropriate. For this the `bypassTagCacheOnCacheHit` option is being added to the `RegionalCache` class. + +Example: + +```js +import { defineCloudflareConfig } from "@opennextjs/cloudflare"; +import d1NextTagCache from "@opennextjs/cloudflare/overrides/tag-cache/d1-next-tag-cache"; +import memoryQueue from "@opennextjs/cloudflare/overrides/queue/memory-queue"; +import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache"; +import { withRegionalCache } from "@opennextjs/cloudflare/overrides/incremental-cache/regional-cache"; + +export default defineCloudflareConfig({ + incrementalCache: withRegionalCache(r2IncrementalCache, { + mode: "long-lived", + bypassTagCacheOnCacheHit: true, + }), + tagCache: d1NextTagCache, + queue: memoryQueue, +}); +``` diff --git a/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts b/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts index af1835f5..a2a98ba9 100644 --- a/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts +++ b/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts @@ -38,6 +38,15 @@ type Options = { * @default `false` for the `short-lived` mode, and `true` for the `long-lived` mode. */ shouldLazilyUpdateOnCacheHit?: boolean; + + /** + * Whether on cache hits the tagCache should be skipped or not. Skipping the tagCache allows requests to be + * handled faster, the downside of this is that you need to make sure that the cache gets correctly purged + * either by enabling the auto cache purging feature or doing that manually. + * + * @default `true` if the auto cache purging is enabled, `false` otherwise. + */ + bypassTagCacheOnCacheHit?: boolean; }; interface PutToCacheInput { @@ -65,6 +74,17 @@ class RegionalCache implements IncrementalCache { this.opts.shouldLazilyUpdateOnCacheHit ??= this.opts.mode === "long-lived"; } + get #bypassTagCacheOnCacheHit(): boolean { + if (this.opts.bypassTagCacheOnCacheHit !== undefined) { + // If the bypassTagCacheOnCacheHit option is set we return that one + return this.opts.bypassTagCacheOnCacheHit; + } + + // Otherwise we default to whether the automatic cache purging is enabled or not + const hasAutomaticCachePurging = !!getCloudflareContext().env.NEXT_CACHE_DO_PURGE; + return hasAutomaticCachePurging; + } + async get( key: string, cacheType?: CacheType @@ -91,7 +111,12 @@ class RegionalCache implements IncrementalCache { ); } - return cachedResponse.json(); + const responseJson: Record = await cachedResponse.json(); + + return { + ...responseJson, + shouldBypassTagCache: this.#bypassTagCacheOnCacheHit, + }; } const rawEntry = await this.store.get(key, cacheType);