fix(seeds): extend seed-meta TTL alongside data keys on fetch failure (#1724)

When upstream APIs fail and seeds extend existing data key TTLs, the
seed-meta key was left untouched. Health checks use seed-meta fetchedAt
to determine staleness, so preserved data still triggered STALE_SEED
warnings even though the data was valid.

Now all TTL extension paths include the corresponding seed-meta key:
- _seed-utils.mjs runSeed() (fetch failure + validation skip)
- fetch-gpsjam.mjs (Wingbits 500 fallback)
- seed-airport-delays.mjs (FAA fetch failure)
- seed-military-flights.mjs (OpenSky fetch failure)
- seed-service-statuses.mjs (RPC fetch failure)
This commit is contained in:
Elie Habib
2026-03-17 06:35:12 +04:00
committed by GitHub
parent 10f619326e
commit 9e58365587
5 changed files with 6 additions and 6 deletions

View File

@@ -322,7 +322,7 @@ export async function runSeed(domain, resource, canonicalKey, fetchFn, opts = {}
console.error(` FETCH FAILED: ${err.message || err}${cause}`);
const ttl = ttlSeconds || 600;
const keys = [canonicalKey];
const keys = [canonicalKey, `seed-meta:${domain}:${resource}`];
if (extraKeys) keys.push(...extraKeys.map(ek => ek.key));
await extendExistingTtl(keys, ttl);
@@ -335,7 +335,7 @@ export async function runSeed(domain, resource, canonicalKey, fetchFn, opts = {}
const publishResult = await atomicPublish(canonicalKey, data, validateFn, ttlSeconds);
if (publishResult.skipped) {
const durationMs = Date.now() - startMs;
const keys = [canonicalKey];
const keys = [canonicalKey, `seed-meta:${domain}:${resource}`];
if (extraKeys) keys.push(...extraKeys.map(ek => ek.key));
await extendExistingTtl(keys, ttlSeconds || 600);
console.log(` SKIPPED: validation failed (empty data) — extended existing cache TTL`);

View File

@@ -257,7 +257,7 @@ async function main() {
body = await fetchWingbits(apiKey);
} catch (err) {
console.error(`[gpsjam] Fetch failed: ${err.message} — extending TTL on stale data`);
await extendExistingTtl([REDIS_KEY_V2, REDIS_KEY_V1], REDIS_TTL);
await extendExistingTtl([REDIS_KEY_V2, REDIS_KEY_V1, 'seed-meta:intelligence:gpsjam'], REDIS_TTL);
process.exit(0);
}

View File

@@ -274,7 +274,7 @@ async function main() {
} catch (err) {
await releaseLock('aviation:delays', runId);
console.error(` FETCH FAILED: ${err.message || err}`);
await extendExistingTtl([FAA_CACHE_KEY, NOTAM_CACHE_KEY], CACHE_TTL);
await extendExistingTtl([FAA_CACHE_KEY, NOTAM_CACHE_KEY, 'seed-meta:aviation:delays'], CACHE_TTL);
console.log(`\n=== Failed gracefully (${Math.round(Date.now() - startMs)}ms) ===`);
process.exit(0);
}

View File

@@ -1287,7 +1287,7 @@ async function main() {
} catch (err) {
await releaseLock('military:flights', runId);
console.error(` FETCH FAILED: ${err.message || err}`);
await extendExistingTtl([LIVE_KEY], LIVE_TTL);
await extendExistingTtl([LIVE_KEY, 'seed-meta:military:flights'], LIVE_TTL);
await extendExistingTtl([STALE_KEY, THEATER_POSTURE_STALE_KEY, MILITARY_SURGES_STALE_KEY, MILITARY_FORECAST_INPUTS_STALE_KEY, MILITARY_CLASSIFICATION_AUDIT_STALE_KEY], STALE_TTL);
await extendExistingTtl([THEATER_POSTURE_LIVE_KEY, MILITARY_FORECAST_INPUTS_LIVE_KEY, MILITARY_CLASSIFICATION_AUDIT_LIVE_KEY], THEATER_POSTURE_LIVE_TTL);
await extendExistingTtl([THEATER_POSTURE_BACKUP_KEY], THEATER_POSTURE_BACKUP_TTL);

View File

@@ -38,7 +38,7 @@ async function warmPing() {
data = await resp.json();
} catch (err) {
console.error(` FETCH FAILED: ${err.message || err}`);
await extendExistingTtl([CANONICAL_KEY], 7200);
await extendExistingTtl([CANONICAL_KEY, 'seed-meta:infra:service-statuses'], 7200);
console.log(`\n=== Failed gracefully (${Math.round(Date.now() - startMs)}ms) ===`);
process.exit(0);
}