From 31a098f2199bebcdea085f7f79645dc90291f783 Mon Sep 17 00:00:00 2001 From: Benjamin Sutter Date: Sun, 30 Aug 2026 18:16:12 +0200 Subject: [PATCH] =?UTF-8?q?fix(livia):=20eigenes=20Zeitlimit=20f=C3=BCr=20?= =?UTF-8?q?die=20Zefix-CSV?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Im Produktionslauf fiel Zefix mit «This operation was aborted» aus, während beide Newsquellen sauber lieferten. Ursache ist die Dateigrösse: 10,5 MB, unkomprimiert, weil der Server kein gzip anbietet. Von einem Schweizer Anschluss dauert der Abruf 1,7 Sekunden, aus dem Rechenzentrum der Anwendung mehr als die fünfzehn, die für die Newsquellen reichlich bemessen sind. Die CSV bekommt deshalb dreissig Sekunden, die HTML-Abrufe behalten fünfzehn. Beides läuft parallel, der Ausfall einer Quelle bleibt folgenlos für die anderen — nur war es bisher immer dieselbe, die ausfiel. Co-Authored-By: Claude Opus 5 (1M context) --- api/_lib/researchSources.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/api/_lib/researchSources.ts b/api/_lib/researchSources.ts index 3c2d352..d38f6ce 100644 --- a/api/_lib/researchSources.ts +++ b/api/_lib/researchSources.ts @@ -47,14 +47,24 @@ const MAX_ARTICLES = 24 const FETCH_CONCURRENCY = 8 const FETCH_TIMEOUT_MS = 15_000 + +/** + * Eigenes Zeitlimit für die Zefix-CSV. + * + * Die Datei ist 10,5 MB gross und wird unkomprimiert ausgeliefert — der Server + * bietet kein gzip an. Von einem Schweizer Anschluss dauert der Abruf keine + * zwei Sekunden, aus dem Rechenzentrum der Anwendung aber mehr als fünfzehn, + * und genau daran ist die Quelle im ersten Produktionslauf gescheitert. + */ +const CSV_TIMEOUT_MS = 30_000 const UA = 'Mozilla/5.0 (compatible; PropertyMatch-LiviaResearch/1.0; +https://property-match-virid.vercel.app)' -async function getText(url: string, extraHeaders: Record = {}): Promise { +async function getText(url: string, timeoutMs: number = FETCH_TIMEOUT_MS): Promise { const ctrl = new AbortController() - const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS) + const timer = setTimeout(() => ctrl.abort(), timeoutMs) try { const res = await fetch(url, { - headers: { 'User-Agent': UA, 'Accept-Language': 'de-CH,de;q=0.9', ...extraHeaders }, + headers: { 'User-Agent': UA, 'Accept-Language': 'de-CH,de;q=0.9' }, redirect: 'follow', signal: ctrl.signal, }) @@ -257,7 +267,7 @@ export async function fetchGreaterZurichResearch(): Promise { * Sache, die Livia nie tun darf. */ export async function fetchZefixResearch(): Promise { - const csv = await getText(SOURCES.ZEFIX.url) + const csv = await getText(SOURCES.ZEFIX.url, CSV_TIMEOUT_MS) const lines = csv.split(/\r?\n/) if (lines.length < 2) throw new Error('CSV enthält keine Daten')