From 4e4fe42c50ad6d7d9e2f7d528e2a650ef392bbdc Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Wed, 13 Aug 2025 18:20:50 +0100 Subject: [PATCH 1/9] fix: make regional cache hits bypass the tagCache When the `regional-cache` is used and it finds an entry, there's no need to then interact with the `tagCache`, so the changes here add `shouldBypassTagCache: true` to the cache response to avoid interactions with the tagCache (which can slow down response times) --- .../src/api/overrides/incremental-cache/regional-cache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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..533f9e40 100644 --- a/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts +++ b/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts @@ -103,7 +103,7 @@ class RegionalCache implements IncrementalCache { this.putToCache({ key, cacheType, entry: { value, lastModified } }) ); - return { value, lastModified }; + return { value, lastModified, shouldBypassTagCache: true }; } catch (e) { error("Failed to get from regional cache", e); return null; From df0f1dd5c825ff74437e96af290f5d5f86538c44 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 14 Aug 2025 00:21:07 +0100 Subject: [PATCH 2/9] add `bypassTagCacheOnCacheHit` option --- .changeset/lovely-gifts-cough.md | 26 +++++++++++++++++++ .../incremental-cache/regional-cache.ts | 12 ++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 .changeset/lovely-gifts-cough.md 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 533f9e40..752a9427 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` is the auto cache purging is enabled, `false` otherwise. + */ + bypassTagCacheOnCacheHit?: boolean; }; interface PutToCacheInput { @@ -63,6 +72,7 @@ class RegionalCache implements IncrementalCache { } this.name = this.store.name; this.opts.shouldLazilyUpdateOnCacheHit ??= this.opts.mode === "long-lived"; + this.opts.bypassTagCacheOnCacheHit ??= getCloudflareContext().env.NEXT_CACHE_DO_PURGE ? true : false; } async get( @@ -103,7 +113,7 @@ class RegionalCache implements IncrementalCache { this.putToCache({ key, cacheType, entry: { value, lastModified } }) ); - return { value, lastModified, shouldBypassTagCache: true }; + return { value, lastModified, shouldBypassTagCache: this.opts.bypassTagCacheOnCacheHit }; } catch (e) { error("Failed to get from regional cache", e); return null; From aa204fd1a404548a7e5b0e7b6cd5481f045b347e Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 14 Aug 2025 11:10:34 +0100 Subject: [PATCH 3/9] fix issue of calling `getCloudflareContext` too early --- .../overrides/incremental-cache/regional-cache.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) 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 752a9427..fcc14133 100644 --- a/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts +++ b/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts @@ -72,7 +72,17 @@ class RegionalCache implements IncrementalCache { } this.name = this.store.name; this.opts.shouldLazilyUpdateOnCacheHit ??= this.opts.mode === "long-lived"; - this.opts.bypassTagCacheOnCacheHit ??= getCloudflareContext().env.NEXT_CACHE_DO_PURGE ? true : false; + } + + get #bypassTagCacheOnCacheHit(): boolean { + if (this.opts.bypassTagCacheOnCacheHit) { + // If the bypassTagCacheOnCacheHit option is set we return that one + return this.opts.bypassTagCacheOnCacheHit; + } + + // Otherwise we default to wether the automatic cache purging is enabled or not + const hasAutomaticCachePurging = !!getCloudflareContext().env.NEXT_CACHE_DO_PURGE; + return hasAutomaticCachePurging; } async get( @@ -113,7 +123,7 @@ class RegionalCache implements IncrementalCache { this.putToCache({ key, cacheType, entry: { value, lastModified } }) ); - return { value, lastModified, shouldBypassTagCache: this.opts.bypassTagCacheOnCacheHit }; + return { value, lastModified, shouldBypassTagCache: this.#bypassTagCacheOnCacheHit }; } catch (e) { error("Failed to get from regional cache", e); return null; From bfd06df5fa18aad16d2204203e70a17dfaafda38 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 14 Aug 2025 13:17:08 +0100 Subject: [PATCH 4/9] Update packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts Co-authored-by: conico974 --- .../src/api/overrides/incremental-cache/regional-cache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fcc14133..04fca853 100644 --- a/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts +++ b/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts @@ -44,7 +44,7 @@ type Options = { * 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` is the auto cache purging is enabled, `false` otherwise. + * @default `true` if the auto cache purging is enabled, `false` otherwise. */ bypassTagCacheOnCacheHit?: boolean; }; From 49cd870aab67121e3e08722cbf90939c9e047c3d Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 14 Aug 2025 13:18:14 +0100 Subject: [PATCH 5/9] update incorrect check --- .../src/api/overrides/incremental-cache/regional-cache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 04fca853..5cb58ff4 100644 --- a/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts +++ b/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts @@ -75,7 +75,7 @@ class RegionalCache implements IncrementalCache { } get #bypassTagCacheOnCacheHit(): boolean { - if (this.opts.bypassTagCacheOnCacheHit) { + if (this.opts.bypassTagCacheOnCacheHit !== undefined) { // If the bypassTagCacheOnCacheHit option is set we return that one return this.opts.bypassTagCacheOnCacheHit; } From c0f8405f9509090453f32867fa49b271daaec8f4 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 15 Aug 2025 18:02:40 +0100 Subject: [PATCH 6/9] also pass `shouldBypassTagCache` flag on r2 hits --- .../src/api/overrides/incremental-cache/regional-cache.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 5cb58ff4..bda8a61d 100644 --- a/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts +++ b/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts @@ -111,7 +111,10 @@ class RegionalCache implements IncrementalCache { ); } - return cachedResponse.json(); + return { + ...cachedResponse.json(), + shouldBypassTagCache: this.#bypassTagCacheOnCacheHit, + }; } const rawEntry = await this.store.get(key, cacheType); From fcb325ea4ae65284125454a51bd4c844af45d492 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 15 Aug 2025 18:39:14 +0100 Subject: [PATCH 7/9] Fix typo Co-authored-by: James Anderson --- .../src/api/overrides/incremental-cache/regional-cache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 bda8a61d..a6441c42 100644 --- a/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts +++ b/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts @@ -80,7 +80,7 @@ class RegionalCache implements IncrementalCache { return this.opts.bypassTagCacheOnCacheHit; } - // Otherwise we default to wether the automatic cache purging is enabled or not + // Otherwise we default to whether the automatic cache purging is enabled or not const hasAutomaticCachePurging = !!getCloudflareContext().env.NEXT_CACHE_DO_PURGE; return hasAutomaticCachePurging; } From 23d262d081cc56991038976210b3d08c5ec80f81 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Sun, 17 Aug 2025 00:12:34 +0100 Subject: [PATCH 8/9] remove incorrect shouldBypassTagCache --- .../src/api/overrides/incremental-cache/regional-cache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a6441c42..75715246 100644 --- a/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts +++ b/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts @@ -126,7 +126,7 @@ class RegionalCache implements IncrementalCache { this.putToCache({ key, cacheType, entry: { value, lastModified } }) ); - return { value, lastModified, shouldBypassTagCache: this.#bypassTagCacheOnCacheHit }; + return { value, lastModified }; } catch (e) { error("Failed to get from regional cache", e); return null; From 6082569c1c89e7a1d9b1faf544ba3558f15e4d16 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Mon, 18 Aug 2025 10:53:42 +0100 Subject: [PATCH 9/9] properly await json --- .../src/api/overrides/incremental-cache/regional-cache.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 75715246..a2a98ba9 100644 --- a/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts +++ b/packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts @@ -111,8 +111,10 @@ class RegionalCache implements IncrementalCache { ); } + const responseJson: Record = await cachedResponse.json(); + return { - ...cachedResponse.json(), + ...responseJson, shouldBypassTagCache: this.#bypassTagCacheOnCacheHit, }; }