From 33de634ee798291c5d049f70d618d018a991bb1a Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Fri, 17 Oct 2025 18:47:30 +0200 Subject: [PATCH 1/2] Fix cache race condition --- packages/gitbook/open-next.config.ts | 4 ++-- .../{ => incrementalCache}/incrementalCache.ts | 14 ++------------ .../openNext/incrementalCache/middleware.ts | 12 ++++++++++++ .../gitbook/openNext/incrementalCache/server.ts | 13 +++++++++++++ 4 files changed, 29 insertions(+), 14 deletions(-) rename packages/gitbook/openNext/{ => incrementalCache}/incrementalCache.ts (90%) create mode 100644 packages/gitbook/openNext/incrementalCache/middleware.ts create mode 100644 packages/gitbook/openNext/incrementalCache/server.ts diff --git a/packages/gitbook/open-next.config.ts b/packages/gitbook/open-next.config.ts index 1872309119..3ac1228c46 100644 --- a/packages/gitbook/open-next.config.ts +++ b/packages/gitbook/open-next.config.ts @@ -7,7 +7,7 @@ export default { converter: 'edge', proxyExternalRequest: 'fetch', queue: () => import('./openNext/queue/middleware').then((m) => m.default), - incrementalCache: () => import('./openNext/incrementalCache').then((m) => m.default), + incrementalCache: () => import('./openNext/incrementalCache/server').then((m) => m.default), tagCache: () => import('./openNext/tagCache/middleware').then((m) => m.default), }, }, @@ -18,7 +18,7 @@ export default { converter: 'edge', proxyExternalRequest: 'fetch', queue: () => import('./openNext/queue/middleware').then((m) => m.default), - incrementalCache: () => import('./openNext/incrementalCache').then((m) => m.default), + incrementalCache: () => import('./openNext/incrementalCache/middleware').then((m) => m.default), tagCache: () => import('./openNext/tagCache/middleware').then((m) => m.default), }, }, diff --git a/packages/gitbook/openNext/incrementalCache.ts b/packages/gitbook/openNext/incrementalCache/incrementalCache.ts similarity index 90% rename from packages/gitbook/openNext/incrementalCache.ts rename to packages/gitbook/openNext/incrementalCache/incrementalCache.ts index 9fde1fc41d..ff0a28c719 100644 --- a/packages/gitbook/openNext/incrementalCache.ts +++ b/packages/gitbook/openNext/incrementalCache/incrementalCache.ts @@ -7,7 +7,6 @@ import type { } from '@opennextjs/aws/types/overrides.js'; import { getCloudflareContext } from '@opennextjs/cloudflare'; -import { withRegionalCache } from '@opennextjs/cloudflare/overrides/incremental-cache/regional-cache'; import type { DurableObjectNamespace, Rpc } from '@cloudflare/workers-types'; @@ -23,7 +22,7 @@ export type KeyOptions = { * It is very similar to the `R2IncrementalCache` in the `@opennextjs/cloudflare` package, but it has an additional * R2WriteBuffer Durable Object to handle writes to R2. Given how we set up cache, we often end up writing to the same key too fast. */ -class GitbookIncrementalCache implements IncrementalCache { +export class GitbookIncrementalCache implements IncrementalCache { name = 'GitbookIncrementalCache'; async get( @@ -136,13 +135,4 @@ class GitbookIncrementalCache implements IncrementalCache { '/' ); } -} - -export default withRegionalCache(new GitbookIncrementalCache(), { - mode: 'long-lived', - // We can do it because we use our own logic to invalidate the cache - bypassTagCacheOnCacheHit: true, - defaultLongLivedTtlSec: 60 * 60 * 24 /* 24 hours */, - // We don't want to update the cache entry on every cache hit - shouldLazilyUpdateOnCacheHit: false, -}); +} \ No newline at end of file diff --git a/packages/gitbook/openNext/incrementalCache/middleware.ts b/packages/gitbook/openNext/incrementalCache/middleware.ts new file mode 100644 index 0000000000..e088a88c52 --- /dev/null +++ b/packages/gitbook/openNext/incrementalCache/middleware.ts @@ -0,0 +1,12 @@ +import { withRegionalCache } from "@opennextjs/cloudflare/overrides/incremental-cache/regional-cache"; +import { GitbookIncrementalCache } from "./incrementalCache"; + + +export default withRegionalCache(new GitbookIncrementalCache(), { + mode: 'long-lived', + // We can do it because we use our own logic to invalidate the cache + bypassTagCacheOnCacheHit: true, + defaultLongLivedTtlSec: 60 * 60 * 24 /* 24 hours */, + // We don't want to update the cache entry on every cache hit + shouldLazilyUpdateOnCacheHit: false, +}); diff --git a/packages/gitbook/openNext/incrementalCache/server.ts b/packages/gitbook/openNext/incrementalCache/server.ts new file mode 100644 index 0000000000..f567a7b8c3 --- /dev/null +++ b/packages/gitbook/openNext/incrementalCache/server.ts @@ -0,0 +1,13 @@ +import { withRegionalCache } from "@opennextjs/cloudflare/overrides/incremental-cache/regional-cache"; +import { GitbookIncrementalCache } from "./incrementalCache"; + + +export default withRegionalCache(new GitbookIncrementalCache(), { + mode: 'long-lived', + // Because of a race condition, the middleware may have populated the cache entry before `cache.match` had time to run on the server. + // TODO: We should bypass the incremental cache entirely when the interceptor has caught the request. Should be done in OpenNext. + bypassTagCacheOnCacheHit: false, + defaultLongLivedTtlSec: 60 * 60 * 24 /* 24 hours */, + // We don't want to update the cache entry on every cache hit + shouldLazilyUpdateOnCacheHit: false, +}); From 8aa0dc187263c83ddde8163037867effac5024f7 Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Fri, 17 Oct 2025 18:53:52 +0200 Subject: [PATCH 2/2] linting --- packages/gitbook/open-next.config.ts | 6 ++++-- .../gitbook/openNext/incrementalCache/incrementalCache.ts | 3 +-- packages/gitbook/openNext/incrementalCache/middleware.ts | 5 ++--- packages/gitbook/openNext/incrementalCache/server.ts | 5 ++--- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/gitbook/open-next.config.ts b/packages/gitbook/open-next.config.ts index 3ac1228c46..f4f5c25dff 100644 --- a/packages/gitbook/open-next.config.ts +++ b/packages/gitbook/open-next.config.ts @@ -7,7 +7,8 @@ export default { converter: 'edge', proxyExternalRequest: 'fetch', queue: () => import('./openNext/queue/middleware').then((m) => m.default), - incrementalCache: () => import('./openNext/incrementalCache/server').then((m) => m.default), + incrementalCache: () => + import('./openNext/incrementalCache/server').then((m) => m.default), tagCache: () => import('./openNext/tagCache/middleware').then((m) => m.default), }, }, @@ -18,7 +19,8 @@ export default { converter: 'edge', proxyExternalRequest: 'fetch', queue: () => import('./openNext/queue/middleware').then((m) => m.default), - incrementalCache: () => import('./openNext/incrementalCache/middleware').then((m) => m.default), + incrementalCache: () => + import('./openNext/incrementalCache/middleware').then((m) => m.default), tagCache: () => import('./openNext/tagCache/middleware').then((m) => m.default), }, }, diff --git a/packages/gitbook/openNext/incrementalCache/incrementalCache.ts b/packages/gitbook/openNext/incrementalCache/incrementalCache.ts index ff0a28c719..11c0f89774 100644 --- a/packages/gitbook/openNext/incrementalCache/incrementalCache.ts +++ b/packages/gitbook/openNext/incrementalCache/incrementalCache.ts @@ -7,7 +7,6 @@ import type { } from '@opennextjs/aws/types/overrides.js'; import { getCloudflareContext } from '@opennextjs/cloudflare'; - import type { DurableObjectNamespace, Rpc } from '@cloudflare/workers-types'; export const BINDING_NAME = 'NEXT_INC_CACHE_R2_BUCKET'; @@ -135,4 +134,4 @@ export class GitbookIncrementalCache implements IncrementalCache { '/' ); } -} \ No newline at end of file +} diff --git a/packages/gitbook/openNext/incrementalCache/middleware.ts b/packages/gitbook/openNext/incrementalCache/middleware.ts index e088a88c52..2204ae4c68 100644 --- a/packages/gitbook/openNext/incrementalCache/middleware.ts +++ b/packages/gitbook/openNext/incrementalCache/middleware.ts @@ -1,6 +1,5 @@ -import { withRegionalCache } from "@opennextjs/cloudflare/overrides/incremental-cache/regional-cache"; -import { GitbookIncrementalCache } from "./incrementalCache"; - +import { withRegionalCache } from '@opennextjs/cloudflare/overrides/incremental-cache/regional-cache'; +import { GitbookIncrementalCache } from './incrementalCache'; export default withRegionalCache(new GitbookIncrementalCache(), { mode: 'long-lived', diff --git a/packages/gitbook/openNext/incrementalCache/server.ts b/packages/gitbook/openNext/incrementalCache/server.ts index f567a7b8c3..87c4963254 100644 --- a/packages/gitbook/openNext/incrementalCache/server.ts +++ b/packages/gitbook/openNext/incrementalCache/server.ts @@ -1,6 +1,5 @@ -import { withRegionalCache } from "@opennextjs/cloudflare/overrides/incremental-cache/regional-cache"; -import { GitbookIncrementalCache } from "./incrementalCache"; - +import { withRegionalCache } from '@opennextjs/cloudflare/overrides/incremental-cache/regional-cache'; +import { GitbookIncrementalCache } from './incrementalCache'; export default withRegionalCache(new GitbookIncrementalCache(), { mode: 'long-lived',