Make fewer IQ Bible calls
- Load the narrator list only when the audio dropdown is opened - Keep today's verse and devotional in memory for an hour (not saved) - Back off for a minute after 'allowance used up' or unreachable; keep 'nothing here' answers - Server shares one upstream call between identical simultaneous requests (nothing stored) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d29a66f984
commit
31ac6b9179
7 files changed
+129
-17
No files matched your search
+21
-4
@@ -89,6 +89,24 @@ async function cacheTtl(headers, isText) {
|
||||
const cache = new Map(); // key -> { at, status, type, body }
|
||||
const CACHE_MAX = 1500;
|
||||
|
||||
// Requests for the same thing that arrive while one is already on its way share that one call. Nothing is kept
|
||||
// afterwards (that would be caching), so this spends less of the allowance without touching the API's terms.
|
||||
const inflight = new Map(); // upstream path -> Promise of { status, type, body, retryAfter }
|
||||
function fetchOnce(key, headers) {
|
||||
let p = inflight.get(key);
|
||||
if (!p) {
|
||||
p = (async () => {
|
||||
const upstream = await fetch(`${BASE()}${key}`, { headers, signal: AbortSignal.timeout(20_000) });
|
||||
return {
|
||||
status: upstream.status, ok: upstream.ok, retryAfter: upstream.headers.get('retry-after'),
|
||||
type: upstream.headers.get('content-type') || 'application/json', body: Buffer.from(await upstream.arrayBuffer()),
|
||||
};
|
||||
})().finally(() => inflight.delete(key));
|
||||
inflight.set(key, p);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
const hits = new Map(); // `${userId}:${bucket}` -> { n, resetAt }
|
||||
function overLimit(userId, heavy) {
|
||||
const bucket = heavy ? 'h' : 'n';
|
||||
@@ -119,12 +137,11 @@ export function registerIqBibleRoutes(app, requireAuth) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const upstream = await fetch(`${BASE()}${target.key}`, { headers, signal: AbortSignal.timeout(20_000) });
|
||||
const body = Buffer.from(await upstream.arrayBuffer());
|
||||
const type = upstream.headers.get('content-type') || 'application/json';
|
||||
const upstream = await fetchOnce(target.key, headers);
|
||||
const { body, type } = upstream;
|
||||
if (upstream.status === 401) return res.status(502).json({ error: 'The IQ Bible key was rejected. Check IQBIBLE_API_KEY.' });
|
||||
if (upstream.status === 429) {
|
||||
const retry = upstream.headers.get('retry-after');
|
||||
const retry = upstream.retryAfter;
|
||||
if (retry) res.set('Retry-After', retry);
|
||||
return res.status(429).json({ error: 'The IQ Bible allowance is used up for now. Try again later.' });
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user