fix(canvas3d): retry transient poll failures before fail state

This commit is contained in:
134 2026-08-18 16:53:28 +08:00
parent 1fa126cecf
commit 7602365bb8

View File

@ -850,9 +850,21 @@ export default function CanvasModel3DPage() {
);
const pollAttemptsRef = useRef(0);
const pollErrorCountRef = useRef(0);
const multiViewSlotsRef = useRef<MultiViewSlot[]>([]);
const batchImageSlotsRef = useRef<MultiViewSlot[]>([]);
const MAX_RETRYABLE_TASK_POLL_FAILURES = 12;
const isRetryableTaskPollFailure = (message: string) => {
const normalized = String(message || "").toLowerCase();
return (
/http[^0-9]*5\d\d/.test(normalized) ||
normalized.includes("超时") ||
normalized.includes("timeout")
);
};
// Fetch site settings for Logo
const { data: siteSettingsData } = useSWR(
"/api/site-settings?scope=branding",
@ -1434,6 +1446,33 @@ export default function CanvasModel3DPage() {
});
if (!result.success || !result.data) {
const failMessage = result.error || "任务查询失败";
if (isRetryableTaskPollFailure(failMessage)) {
pollErrorCountRef.current += 1;
if (pollErrorCountRef.current === 1) {
console.warn("[Model3DPage] 任务查询临时异常,继续重试", {
taskId: currentTask.taskId,
provider: currentTask.provider,
error: failMessage,
attempt: pollAttemptsRef.current,
});
toast.info(`任务查询异常,正在重试...`);
}
if (pollErrorCountRef.current >= MAX_RETRYABLE_TASK_POLL_FAILURES) {
const failedRecord: TaskRecord = {
...currentTask,
status: "failed",
error: `${failMessage}(重试仍异常)`,
};
setCurrentTask(failedRecord);
upsertTaskHistory(failedRecord);
}
return;
}
pollErrorCountRef.current = 0;
const failedRecord: TaskRecord = {
...currentTask,
status: "failed",
@ -1479,6 +1518,8 @@ export default function CanvasModel3DPage() {
error:
status === "failed" ? result.data.errorMessage || "任务失败" : null,
};
pollErrorCountRef.current = 0;
if (taskRecordChanged(currentTask, nextRecord)) {
setCurrentTask(nextRecord);
upsertTaskHistory(nextRecord);