fix(report-ui): ретрай docx-preflight против 502-гонки сразу после ready (#2353)
All checks were successful
Deploy / changes (push) Successful in 8s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 3m26s
Deploy / deploy (push) Successful in 1m19s

This commit is contained in:
bot-backend 2026-07-04 00:03:12 +00:00
parent 7ebeddc2bc
commit c778e4c85d

View file

@ -122,17 +122,30 @@ function triggerAnchorDownload(cad: string, format: ReportFormat): void {
async function triggerReportDownload(
cad: string,
format: ReportFormat,
onError: () => void,
onError: (message: string) => void,
): Promise<void> {
if (format === "pdf") {
triggerAnchorDownload(cad, "pdf");
return;
}
try {
const res = await fetch(downloadUrl(cad, "docx"), { method: "HEAD" });
// Любой не-OK (404 легаси-рана, 5xx) — не даём <a> молча скачать страницу ошибки.
let res = await fetch(downloadUrl(cad, "docx"), { method: "HEAD" });
// 5xx сразу после status=ready — транзиентная proxy-гонка (стресс-свип
// 2026-07-04: первый HEAD после ready ловил 502, ретрей через ~1.5с — 200).
// Один ретрай, прежде чем показывать пользователю ошибку.
if (!res.ok && res.status !== 404) {
await new Promise((r) => setTimeout(r, 1500));
res = await fetch(downloadUrl(cad, "docx"), { method: "HEAD" });
}
if (res.status === 404) {
// Легаси-ран без docx_path — честная просьба пересобрать.
onError("Пересоберите отчёт — DOCX для старого прогона отсутствует");
return;
}
if (!res.ok) {
onError();
// Устойчивый не-OK (5xx и после ретрая) — не даём <a> молча скачать
// страницу ошибки, но и НЕ просим пересобрать (файл скорее всего цел).
onError("Не удалось скачать отчёт — повторите через минуту");
return;
}
} catch {
@ -160,10 +173,8 @@ export function useFullReport(cad: string): UseFullReportResult {
const pendingFormatRef = useRef<ReportFormat>("pdf");
// Стабильный колбэк ошибки docx-download'а для triggerReportDownload.
const handleDownloadError = useCallback(() => {
setDownloadError(
"Пересоберите отчёт — DOCX для старого прогона отсутствует",
);
const handleDownloadError = useCallback((message: string) => {
setDownloadError(message);
}, []);
// ── POST enqueue ────────────────────────────────────────────────────────────