fix(report-ui): ретрай docx-preflight против 502-гонки сразу после ready
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 59s
CI / openapi-codegen-check (pull_request) Successful in 1m59s

Стресс-свип 2026-07-04 (7 участков): первый HEAD download сразу после
status=ready может словить транзиентный 502 (proxy-гонка на моменте
записи файла), ретрей через ~30с — чистый 200. Прежний preflight по
!res.ok показывал на это «Пересоберите отчёт» — вводит в заблуждение,
файл цел. Теперь: 5xx → один ретрай через 1.5с; устойчивый не-OK →
честное «Не удалось скачать — повторите через минуту»; 404 (легаси-ран
без docx) — прежняя просьба пересобрать. onError теперь несёт message.
This commit is contained in:
bot-backend 2026-07-04 05:00:09 +05:00
parent 36fe33750f
commit 786739f0a6

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 ────────────────────────────────────────────────────────────