fix(tech-events): prevent partial fetch results from being cached (#1473)

Techmeme ICS and dev.events RSS fetches on Vercel edge can partially
fail (timeout, truncation), returning only 1 event instead of 20+.
The handler cached this partial result for 6 hours, causing the Tech
Events panel to show empty.

- Add 8s AbortSignal.timeout on both external fetches
- Require minimum 5 events before caching (at least curated count)
This commit is contained in:
Elie Habib
2026-03-12 07:44:20 +04:00
committed by GitHub
parent 876c06455f
commit 9f8f651d20

View File

@@ -259,13 +259,15 @@ async function fetchTechEvents(req: ListTechEventsRequest): Promise<ListTechEven
const limit = clampInt(req.limit, 50, 1, 200);
const days = clampInt(req.days, 90, 1, 365);
// Fetch both sources in parallel
// Fetch both sources in parallel with timeouts
const [icsResponse, rssResponse] = await Promise.allSettled([
fetch(ICS_URL, {
headers: { 'User-Agent': CHROME_UA },
signal: AbortSignal.timeout(8000),
}),
fetch(DEV_EVENTS_RSS, {
headers: { 'User-Agent': CHROME_UA },
signal: AbortSignal.timeout(8000),
}),
]);
@@ -363,9 +365,10 @@ export async function listTechEvents(
): Promise<ListTechEventsResponse> {
try {
const cacheKey = `${REDIS_CACHE_KEY}:${req.type || 'all'}:${req.mappable ? 1 : 0}:${req.days || 0}`;
const MIN_EVENTS = 5; // at least curated count; avoid caching partial failures
const result = await cachedFetchJson<ListTechEventsResponse>(cacheKey, REDIS_CACHE_TTL, async () => {
const fetched = await fetchTechEvents({ ...req, limit: 0 });
return fetched.events.length > 0 ? fetched : null;
return fetched.events.length >= MIN_EVENTS ? fetched : null;
});
if (!result) {
return { success: true, count: 0, conferenceCount: 0, mappableCount: 0, lastUpdated: new Date().toISOString(), events: [], error: '' };