fix(jobs): log the maintenance job's caught failures and ship the provider-health strings

This commit is contained in:
Marc-André Bombeck committed 2026-10-08 09:09:04 +02:00
1 parent 5c23f9ed63
commit c8470cc1e6
9 files changed
+40 -73

No files matched your search

-65
View File
@@ -1,65 +0,0 @@
{
"en": {
"admin": {
"providerHealth": {
"statusPaused": "Paused",
"pausedHint": "Paused after repeated failures for {count} users until {at}. It is tried again automatically then.",
"modelNotServed": "The endpoint no longer offers the model {model}. Choose a model it lists in the AI settings."
}
}
},
"de": {
"admin": {
"providerHealth": {
"statusPaused": "Pausiert",
"pausedHint": "Nach wiederholten Fehlern für {count} Nutzer pausiert bis {at}. Danach wird er automatisch wieder versucht.",
"modelNotServed": "Der Endpunkt bietet das Modell {model} nicht mehr an. Wähle in den KI-Einstellungen ein Modell, das er anbietet."
}
}
},
"es": {
"admin": {
"providerHealth": {
"statusPaused": "En pausa",
"pausedHint": "En pausa tras fallos repetidos para {count} usuarios hasta {at}. Después se vuelve a intentar automáticamente.",
"modelNotServed": "El endpoint ya no ofrece el modelo {model}. Elige en los ajustes de IA un modelo que ofrezca."
}
}
},
"fr": {
"admin": {
"providerHealth": {
"statusPaused": "En pause",
"pausedHint": "En pause après des échecs répétés pour {count} utilisateurs jusqu’au {at}. Il sera ensuite réessayé automatiquement.",
"modelNotServed": "Le point d’accès ne propose plus le modèle {model}. Choisissez dans les réglages IA un modèle qu’il propose."
}
}
},
"it": {
"admin": {
"providerHealth": {
"statusPaused": "In pausa",
"pausedHint": "In pausa dopo errori ripetuti per {count} utenti fino al {at}. Poi viene ritentato automaticamente.",
"modelNotServed": "L’endpoint non offre più il modello {model}. Scegli nelle impostazioni IA un modello che offre."
}
}
},
"ko": {
"admin": {
"providerHealth": {
"statusPaused": "일시 중지됨",
"pausedHint": "반복된 오류로 사용자 {count}명에 대해 {at}까지 일시 중지되었습니다. 그 후 자동으로 다시 시도합니다.",
"modelNotServed": "엔드포인트가 더 이상 {model} 모델을 제공하지 않습니다. AI 설정에서 제공되는 모델을 선택하세요."
}
}
},
"pl": {
"admin": {
"providerHealth": {
"statusPaused": "Wstrzymany",
"pausedHint": "Wstrzymany po powtarzających się błędach dla {count} użytkowników do {at}. Potem zostanie automatycznie ponowiony.",
"modelNotServed": "Punkt końcowy nie oferuje już modelu {model}. Wybierz w ustawieniach AI model, który oferuje."
}
}
}
}
+4 -1
View File
@@ -7188,7 +7188,10 @@
"typeCodex": "ChatGPT-Anmeldung (persönlich)",
"typeLocal": "Lokales Modell (persönlich)",
"typeGateway": "OpenAI-kompatibles Gateway (persönlich)",
"spendToday": "Heute ({date}): {total} Tokens, davon {operator} auf dem Schlüssel des Betreibers."
"spendToday": "Heute ({date}): {total} Tokens, davon {operator} auf dem Schlüssel des Betreibers.",
"statusPaused": "Pausiert",
"pausedHint": "Nach wiederholten Fehlern für {count} Nutzer pausiert bis {at}. Danach wird er automatisch wieder versucht.",
"modelNotServed": "Der Endpunkt bietet das Modell {model} nicht mehr an. Wähle in den KI-Einstellungen ein Modell, das er anbietet."
},
"aiQuality": {
"title": "Auswertungs-Qualität",
+4 -1
View File
@@ -7188,7 +7188,10 @@
"typeCodex": "ChatGPT sign-in (personal)",
"typeLocal": "Local model (personal)",
"typeGateway": "OpenAI-compatible gateway (personal)",
"spendToday": "Today ({date}): {total} tokens, {operator} of them on the operator's own key."
"spendToday": "Today ({date}): {total} tokens, {operator} of them on the operator's own key.",
"statusPaused": "Paused",
"pausedHint": "Paused after repeated failures for {count} users until {at}. It is tried again automatically then.",
"modelNotServed": "The endpoint no longer offers the model {model}. Choose a model it lists in the AI settings."
},
"aiQuality": {
"title": "Insights Quality",
+4 -1
View File
@@ -7188,7 +7188,10 @@
"typeCodex": "Inicio de sesión de ChatGPT (personal)",
"typeLocal": "Modelo local (personal)",
"typeGateway": "Pasarela compatible con OpenAI (personal)",
"spendToday": "Hoy ({date}): {total} tokens, {operator} de ellos en la clave del operador."
"spendToday": "Hoy ({date}): {total} tokens, {operator} de ellos en la clave del operador.",
"statusPaused": "En pausa",
"pausedHint": "En pausa tras fallos repetidos para {count} usuarios hasta {at}. Después se vuelve a intentar automáticamente.",
"modelNotServed": "El endpoint ya no ofrece el modelo {model}. Elige en los ajustes de IA un modelo que ofrezca."
},
"aiQuality": {
"title": "Calidad de los análisis",
+4 -1
View File
@@ -7188,7 +7188,10 @@
"typeCodex": "Connexion ChatGPT (personnelle)",
"typeLocal": "Modèle local (personnel)",
"typeGateway": "Passerelle compatible OpenAI (personnelle)",
"spendToday": "Aujourd'hui ({date}) : {total} jetons, dont {operator} sur la clé de l'opérateur."
"spendToday": "Aujourd'hui ({date}) : {total} jetons, dont {operator} sur la clé de l'opérateur.",
"statusPaused": "En pause",
"pausedHint": "En pause après des échecs répétés pour {count} utilisateurs jusqu’au {at}. Il sera ensuite réessayé automatiquement.",
"modelNotServed": "Le point d’accès ne propose plus le modèle {model}. Choisissez dans les réglages IA un modèle qu’il propose."
},
"aiQuality": {
"title": "Qualité des analyses",
+4 -1
View File
@@ -7188,7 +7188,10 @@
"typeCodex": "Accesso ChatGPT (personale)",
"typeLocal": "Modello locale (personale)",
"typeGateway": "Gateway compatibile OpenAI (personale)",
"spendToday": "Oggi ({date}): {total} token, di cui {operator} sulla chiave dell'operatore."
"spendToday": "Oggi ({date}): {total} token, di cui {operator} sulla chiave dell'operatore.",
"statusPaused": "In pausa",
"pausedHint": "In pausa dopo errori ripetuti per {count} utenti fino al {at}. Poi viene ritentato automaticamente.",
"modelNotServed": "L’endpoint non offre più il modello {model}. Scegli nelle impostazioni IA un modello che offre."
},
"aiQuality": {
"title": "Qualità delle analisi",
+4 -1
View File
@@ -7870,7 +7870,10 @@
"typeCodex": "ChatGPT 로그인 (개인)",
"typeLocal": "로컬 모델 (개인)",
"typeGateway": "OpenAI 호환 게이트웨이 (개인)",
"spendToday": "오늘({date}): 토큰 {total}개, 그중 {operator}개는 운영자 키에서 사용되었습니다."
"spendToday": "오늘({date}): 토큰 {total}개, 그중 {operator}개는 운영자 키에서 사용되었습니다.",
"statusPaused": "일시 중지됨",
"pausedHint": "반복된 오류로 사용자 {count}명에 대해 {at}까지 일시 중지되었습니다. 그 후 자동으로 다시 시도합니다.",
"modelNotServed": "엔드포인트가 더 이상 {model} 모델을 제공하지 않습니다. AI 설정에서 제공되는 모델을 선택하세요."
},
"cardError": {
"title": "페이지의 이 부분을 표시할 수 없습니다",
+4 -1
View File
@@ -7188,7 +7188,10 @@
"typeCodex": "Logowanie ChatGPT (osobiste)",
"typeLocal": "Model lokalny (osobisty)",
"typeGateway": "Brama zgodna z OpenAI (osobista)",
"spendToday": "Dzisiaj ({date}): {total} tokenów, w tym {operator} na kluczu operatora."
"spendToday": "Dzisiaj ({date}): {total} tokenów, w tym {operator} na kluczu operatora.",
"statusPaused": "Wstrzymany",
"pausedHint": "Wstrzymany po powtarzających się błędach dla {count} użytkowników do {at}. Potem zostanie automatycznie ponowiony.",
"modelNotServed": "Punkt końcowy nie oferuje już modelu {model}. Wybierz w ustawieniach AI model, który oferuje."
},
"aiQuality": {
"title": "Jakość analiz",
+12 -1
View File
@@ -40,6 +40,7 @@ import { withJobLock } from "@/lib/jobs/job-lock";
import { jobDone, jobFailed, type JobOutcome } from "@/lib/jobs/job-outcome";
import { reportJobRun, type JobRunCandidate } from "@/lib/jobs/job-run-report";
import { withBackgroundEvent } from "@/lib/logging/background";
import { logCaught } from "@/lib/logging/signal";
export const MEASUREMENT_MAINTENANCE_QUEUE = "measurement-maintenance";
@@ -176,6 +177,7 @@ async function dropInvalidCopies(
ok: true,
});
} catch (err) {
logCaught("measurements.maintenance.drop_invalid_failed", err);
steps.push({
step: "drop_invalid",
target: index.name,
@@ -240,6 +242,7 @@ export async function runMeasurementMaintenance(
ok: true,
});
} catch (err) {
logCaught("measurements.maintenance.vacuum_failed", err);
steps.push({
step: "vacuum",
target: "measurements",
@@ -273,6 +276,7 @@ export async function runMeasurementMaintenance(
ok: true,
});
} catch (err) {
logCaught("measurements.maintenance.reindex_failed", err);
steps.push({
step: "reindex",
target: index.name,
@@ -316,7 +320,14 @@ export async function handleMeasurementMaintenance(
try {
return await runMeasurementMaintenance(client, payload);
} finally {
await client.end().catch(() => {});
await client
.end()
.catch((err) =>
logCaught(
"measurements.maintenance.connection_close_failed",
err,
),
);
}
},
);