From 6ce3cea68272e39fcd17dd7f2816f15bc8ca110b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samy=20Pess=C3=A9?= Date: Thu, 3 Oct 2024 15:46:58 +0200 Subject: [PATCH] Stop using KV cache backend for now, but also improves it for higher performances (#2510) --- .changeset/popular-toys-argue.md | 5 ++ packages/gitbook/src/lib/cache/backends.ts | 4 +- .../gitbook/src/lib/cache/cloudflare-kv.ts | 83 ++++--------------- 3 files changed, 20 insertions(+), 72 deletions(-) create mode 100644 .changeset/popular-toys-argue.md diff --git a/.changeset/popular-toys-argue.md b/.changeset/popular-toys-argue.md new file mode 100644 index 000000000..6198f82b9 --- /dev/null +++ b/.changeset/popular-toys-argue.md @@ -0,0 +1,5 @@ +--- +'gitbook': patch +--- + +Stop using KV cache backend for now, but also improves it for higher performances diff --git a/packages/gitbook/src/lib/cache/backends.ts b/packages/gitbook/src/lib/cache/backends.ts index ba33f23ff..20c54dc53 100644 --- a/packages/gitbook/src/lib/cache/backends.ts +++ b/packages/gitbook/src/lib/cache/backends.ts @@ -1,6 +1,5 @@ import { cloudflareCache } from './cloudflare-cache'; import { cloudflareDOCache } from './cloudflare-do'; -import { cloudflareKVCache } from './cloudflare-kv'; import { memoryCache } from './memory'; export const cacheBackends = [ @@ -10,7 +9,6 @@ export const cacheBackends = [ // Cache local to the datacenter // It can't be purged globally but it's faster cloudflareCache, - // Cache global, but with slow replication - cloudflareKVCache, + // Global cache with slower performances cloudflareDOCache, ]; diff --git a/packages/gitbook/src/lib/cache/cloudflare-kv.ts b/packages/gitbook/src/lib/cache/cloudflare-kv.ts index c4aa270ad..b7e098278 100644 --- a/packages/gitbook/src/lib/cache/cloudflare-kv.ts +++ b/packages/gitbook/src/lib/cache/cloudflare-kv.ts @@ -1,44 +1,15 @@ import type { KVNamespace } from '@cloudflare/workers-types'; -import { CacheBackend, CacheEntry, CacheEntryMeta } from './types'; +import { CacheBackend, CacheEntry, CacheEntryLookup, CacheEntryMeta } from './types'; import { getCacheMaxAge } from './utils'; import { trace } from '../tracing'; -const cacheVersion = 1; +const cacheVersion = 2; interface KVTagMetadata { meta: CacheEntryMeta; } -/** - * As we migrate off KV, we start disabling it for some tests content. - */ -const noKVTags = new Set([ - // docs.gitbook.com - 'url:docs.gitbook.com', - 'site:site_p4Xo4', - 'space:NkEGS7hzeqa35sMXQZ4X', -]); - -function shouldUseKVForTag(tag: string): boolean { - if (noKVTags.has(tag)) { - return false; - } - if (tag.startsWith('change-request:')) { - return false; - } - - // Hash the tag and return true for 95% of the tags - const hash = tag.split('').reduce((acc, char) => { - return acc + char.charCodeAt(0); - }, 0); - if (hash % 100 <= 30) { - return true; - } - - return false; -} - /** * Cache implementation using the Cloudflare KV API. * https://developers.cloudflare.com/kv/ @@ -46,11 +17,7 @@ function shouldUseKVForTag(tag: string): boolean { export const cloudflareKVCache: CacheBackend = { name: 'cloudflare-kv', replication: 'global', - async get({ key, tag }, options) { - if (tag && !shouldUseKVForTag(tag)) { - return null; - } - + async get(entry, options) { const kv = await getKVNamespace(); if (!kv) { return null; @@ -59,19 +26,19 @@ export const cloudflareKVCache: CacheBackend = { return trace( { operation: `cloudflareKV.get`, - name: key, + name: entry.key, }, async (span) => { - const kvKey = getValueKey(key); + const kvKey = getKey(entry); - const entry = await kv.get(kvKey, { + const kvEntry = await kv.get(kvKey, { type: 'json', cacheTtl: 60, }); - span.setAttribute('hit', !!entry); + span.setAttribute('hit', !!kvEntry); - return entry; + return kvEntry; }, ); }, @@ -94,23 +61,10 @@ export const cloudflareKVCache: CacheBackend = { return; } - const kvKey = getValueKey(entry.meta.key); + const kvKey = getKey(entry.meta); await kv.put(kvKey, JSON.stringify(entry), { expirationTtl: secondsFromNow, }); - - if (entry.meta.tag) { - const metadata: KVTagMetadata = { - meta: entry.meta, - }; - const jsonMetadata = JSON.stringify(metadata); - const tagKey = getTagKey(entry.meta.tag, entry.meta.key); - - await kv.put(tagKey, jsonMetadata, { - metadata, - expirationTtl: secondsFromNow, - }); - } }, ); }, @@ -121,8 +75,8 @@ export const cloudflareKVCache: CacheBackend = { } await Promise.all( - entries.map(async ({ key }) => { - const kvKey = getValueKey(key); + entries.map(async (entry) => { + const kvKey = getKey(entry); await kv.delete(kvKey); }), ); @@ -147,12 +101,7 @@ export const cloudflareKVCache: CacheBackend = { for (const entry of entries.keys) { if (entry.metadata) { const metadata = entry.metadata; - const key = metadata.meta.key; - result.push(metadata.meta); - - // Delete the tag key and the value key - pendingDeletions.push(kv.delete(getValueKey(key))); pendingDeletions.push(kv.delete(entry.name)); } } @@ -174,16 +123,12 @@ export const cloudflareKVCache: CacheBackend = { }, }; -function getValueKey(key: string): string { - return `${cacheVersion}.v.${key}`; +function getKey(entry: CacheEntryLookup) { + return `${getTagPrefix(entry.tag || 'default')}.${entry.key}`; } function getTagPrefix(tag: string) { - return `${cacheVersion}.tag.${tag}.`; -} - -function getTagKey(tag: string, key: string) { - return `${getTagPrefix(tag)}${key}`; + return `${cacheVersion}.${tag}.`; } async function getKVNamespace(): Promise {