Stop using KV cache backend for now, but also improves it for higher performances (#2510)

This commit is contained in:
Samy Pessé
2024-10-03 15:46:58 +02:00
committed by GitHub
parent 250e77d18b
commit 6ce3cea682
3 changed files with 20 additions and 72 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'gitbook': patch
---
Stop using KV cache backend for now, but also improves it for higher performances
+1 -3
View File
@@ -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,
];
+14 -69
View File
@@ -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<CacheEntry>(kvKey, {
const kvEntry = await kv.get<CacheEntry>(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<KVNamespace | null> {