akjsdlkasjdlkajlkdjaskljdl
This commit is contained in:
parent
b263580117
commit
b3418d1460
|
|
@ -99,6 +99,12 @@ function cacheKey(id: string): string {
|
||||||
return `profile:${id}`;
|
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<ProfileResult, "source">;
|
type CachedProfile = Omit<ProfileResult, "source">;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -119,11 +125,14 @@ export async function getProfile(
|
||||||
id: string,
|
id: string,
|
||||||
ctx?: ExecutionContext
|
ctx?: ExecutionContext
|
||||||
): Promise<ProfileResult | null> {
|
): Promise<ProfileResult | null> {
|
||||||
const ttl = Math.max(60, Number(env.PROFILE_CACHE_TTL_SECONDS || "300"));
|
|
||||||
const got = await env.PROFILE_CACHE.getWithMetadata(cacheKey(id), "json");
|
const got = await env.PROFILE_CACHE.getWithMetadata(cacheKey(id), "json");
|
||||||
const cached = (got.value as CachedProfile | null) ?? null;
|
const cached = (got.value as CachedProfile | null) ?? null;
|
||||||
const lastWrite = (got.metadata as { t?: number } | null)?.t ?? 0;
|
const meta = got.metadata as { t?: number; ttl?: number } | null;
|
||||||
const cacheFresh = !!cached && Date.now() - lastWrite < ttl * 1000;
|
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.
|
// 1) Fresh rich cache -> serve it without touching Discord at all.
|
||||||
if (cached && cacheFresh) return { ...cached, source: "cache" };
|
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. */
|
/** Persist a rich profile so it can drive cache-hits and bot-merge fallbacks. */
|
||||||
async function writeCache(env: Env, id: string, result: ProfileResult): Promise<void> {
|
async function writeCache(env: Env, id: string, result: ProfileResult): Promise<void> {
|
||||||
|
// 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(
|
await env.PROFILE_CACHE.put(
|
||||||
cacheKey(id),
|
cacheKey(id),
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|
@ -193,7 +204,9 @@ async function writeCache(env: Env, id: string, result: ProfileResult): Promise<
|
||||||
badges: result.badges,
|
badges: result.badges,
|
||||||
connected_accounts: result.connected_accounts,
|
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 } }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,9 @@
|
||||||
// Comma-separated guild IDs the bot is in that you want monitored.
|
// Comma-separated guild IDs the bot is in that you want monitored.
|
||||||
// Leave empty to monitor every guild the bot can see.
|
// Leave empty to monitor every guild the bot can see.
|
||||||
"TRACKED_GUILD_IDS": "",
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue