From b3418d1460dfe203cc721ccc5c143448c41ead4d Mon Sep 17 00:00:00 2001 From: Clove Twilight Date: Fri, 19 Jun 2026 18:58:28 +0100 Subject: [PATCH] akjsdlkasjdlkajlkdjaskljdl --- src/profile.ts | 21 +++++++++++++++++---- wrangler.jsonc | 5 ++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/profile.ts b/src/profile.ts index 90dc35f..12b4caa 100644 --- a/src/profile.ts +++ b/src/profile.ts @@ -99,6 +99,12 @@ function cacheKey(id: string): string { return `profile:${id}`; } +/** Base profile freshness window (seconds). Profiles change rarely, so this is + * long by default; override via PROFILE_CACHE_TTL_SECONDS. */ +function baseTtl(env: Env): number { + return Math.max(60, Number(env.PROFILE_CACHE_TTL_SECONDS || "1800")); +} + type CachedProfile = Omit; /** @@ -119,11 +125,14 @@ export async function getProfile( id: string, ctx?: ExecutionContext ): Promise { - const ttl = Math.max(60, Number(env.PROFILE_CACHE_TTL_SECONDS || "300")); const got = await env.PROFILE_CACHE.getWithMetadata(cacheKey(id), "json"); const cached = (got.value as CachedProfile | null) ?? null; - const lastWrite = (got.metadata as { t?: number } | null)?.t ?? 0; - const cacheFresh = !!cached && Date.now() - lastWrite < ttl * 1000; + const meta = got.metadata as { t?: number; ttl?: number } | null; + const lastWrite = meta?.t ?? 0; + // Per-entry TTL is jittered at write time so a big batch of profiles doesn't + // all go stale on the same tick and stampede the rich refresh. + const entryTtlMs = (meta?.ttl ?? baseTtl(env)) * 1000; + const cacheFresh = !!cached && Date.now() - lastWrite < entryTtlMs; // 1) Fresh rich cache -> serve it without touching Discord at all. if (cached && cacheFresh) return { ...cached, source: "cache" }; @@ -186,6 +195,8 @@ function mergeRichOverBot(cached: CachedProfile, bot: ProfileResult): CachedProf /** Persist a rich profile so it can drive cache-hits and bot-merge fallbacks. */ async function writeCache(env: Env, id: string, result: ProfileResult): Promise { + // Jitter the freshness window ±20% so entries refresh staggered, not in a burst. + const jitteredTtl = Math.round(baseTtl(env) * (0.8 + Math.random() * 0.4)); await env.PROFILE_CACHE.put( cacheKey(id), JSON.stringify({ @@ -193,7 +204,9 @@ async function writeCache(env: Env, id: string, result: ProfileResult): Promise< badges: result.badges, connected_accounts: result.connected_accounts, }), - { expirationTtl: 86400, metadata: { t: Date.now() } } + // Keep the rich blob ~24h so it's available to merge over bot data even + // when it's well past its freshness window. + { expirationTtl: 86400, metadata: { t: Date.now(), ttl: jitteredTtl } } ); } diff --git a/wrangler.jsonc b/wrangler.jsonc index c0ae468..3c17fd6 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -48,6 +48,9 @@ // Comma-separated guild IDs the bot is in that you want monitored. // Leave empty to monitor every guild the bot can see. "TRACKED_GUILD_IDS": "", - "PROFILE_CACHE_TTL_SECONDS": "300" + // Profile freshness window (seconds). Profiles change rarely and the + // user-token /profile route is heavily rate-limited, so keep this long. + // Presence stays live via the gateway regardless of this value. + "PROFILE_CACHE_TTL_SECONDS": "1800" } } \ No newline at end of file