From 67310e9ae551f46e2632846f41ac6ce41a1b3820 Mon Sep 17 00:00:00 2001 From: 134 Date: Wed, 8 Jul 2026 00:25:48 +0800 Subject: [PATCH] fix: timeout scale adjust prep uploads --- app/api/canvas/local-edit/route.ts | 93 ++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 24 deletions(-) diff --git a/app/api/canvas/local-edit/route.ts b/app/api/canvas/local-edit/route.ts index 88f6a0432..69d076539 100644 --- a/app/api/canvas/local-edit/route.ts +++ b/app/api/canvas/local-edit/route.ts @@ -230,6 +230,50 @@ function toArrayBuffer(buffer: Buffer) { ) as ArrayBuffer; } +function getCanvasScaleAdjustPrepUploadTimeoutMs() { + const parsed = Number(process.env.CANVAS_SCALE_ADJUST_PREP_UPLOAD_TIMEOUT_MS); + if (!Number.isFinite(parsed)) return 25_000; + return Math.max(5_000, Math.min(60_000, Math.round(parsed))); +} + +async function uploadScaleAdjustPrepAsset( + filename: string, + buffer: Buffer | null | undefined +): Promise> | null> { + if (!buffer) return null; + const upload = uploadFile(filename, toArrayBuffer(buffer)); + upload.catch((error) => { + console.warn("[Canvas Local Edit] Scale adjust prep asset upload finished after timeout:", { + error: error instanceof Error ? error.message : String(error), + filename, + }); + }); + + let timeoutId: ReturnType | undefined; + const timeout = new Promise((resolve) => { + timeoutId = setTimeout(() => resolve(null), getCanvasScaleAdjustPrepUploadTimeoutMs()); + }); + + try { + const result = await Promise.race([upload, timeout]); + if (!result) { + console.warn("[Canvas Local Edit] Scale adjust prep asset upload timed out; continuing without it:", { + filename, + timeoutMs: getCanvasScaleAdjustPrepUploadTimeoutMs(), + }); + } + return result; + } catch (error) { + console.warn("[Canvas Local Edit] Scale adjust prep asset upload failed:", { + error: error instanceof Error ? error.message : String(error), + filename, + }); + return null; + } finally { + if (timeoutId) clearTimeout(timeoutId); + } +} + function escapeXml(value: string) { return value .replace(/&/g, "&") @@ -3842,22 +3886,17 @@ async function createScaleAdjustPatchReference(params: { filename: string, buffer: Buffer | null | undefined ) => { - if (!buffer) return null; - try { - return await uploadFile(filename, toArrayBuffer(buffer)); - } catch (error) { - console.warn("[Canvas Local Edit] Optional scale adjust asset upload failed:", { - error: error instanceof Error ? error.message : String(error), - filename, - }); - return null; - } + return uploadScaleAdjustPrepAsset(filename, buffer); }; if (params.fullFrameReferenceOnly && structureLockAppliedRef.value) { - const targetDraftFullUpload = await uploadFile( + const targetDraftFullUpload = await uploadScaleAdjustPrepAsset( `canvas-scale-adjust-full-target-draft-${suffix}.jpg`, - toArrayBuffer(targetDraftUploadBuffer) + targetDraftUploadBuffer ); + const fullFrameFallbackUrl = targetDraftFullUpload?.url || sourceImageUrl; + if (!fullFrameFallbackUrl) { + throw new Error("比例调整预处理参考图上传失败,请稍后重试"); + } const productLockOverlayUpload = await uploadOptionalScaleAdjustAsset( `canvas-scale-adjust-product-lock-overlay-${suffix}.png`, targetDraftReference.productLockOverlayBuffer @@ -3897,10 +3936,10 @@ async function createScaleAdjustPatchReference(params: { productLockFalEditMaskUrl: productLockFalEditMaskUpload?.url || null, productLockOverlayUrl: productLockOverlayUpload?.url || null, productLockProtectMaskUrl: productLockProtectMaskUpload?.url || null, - sourceCropUrl: sourceImageUrl || targetDraftFullUpload.url, + sourceCropUrl: sourceImageUrl || fullFrameFallbackUrl, structureLockedDraft: structureLockAppliedRef.value, - targetDraftFullUrl: targetDraftFullUpload.url, - targetDraftUrl: targetDraftFullUpload.url, + targetDraftFullUrl: fullFrameFallbackUrl, + targetDraftUrl: fullFrameFallbackUrl, workspacePixelRect, workspaceRect, }; @@ -3918,17 +3957,17 @@ async function createScaleAdjustPatchReference(params: { ]); const [sourceCropUpload, targetDraftUpload, targetDraftFullUpload] = await Promise.all([ - uploadFile( + uploadScaleAdjustPrepAsset( `canvas-scale-adjust-workspace-source-${suffix}.png`, - toArrayBuffer(sourceCropBuffer) + sourceCropBuffer ), - uploadFile( + uploadScaleAdjustPrepAsset( `canvas-scale-adjust-workspace-target-draft-${suffix}.png`, - toArrayBuffer(targetDraftCropBuffer) + targetDraftCropBuffer ), - uploadFile( + uploadScaleAdjustPrepAsset( `canvas-scale-adjust-full-target-draft-${suffix}.jpg`, - toArrayBuffer(targetDraftUploadBuffer) + targetDraftUploadBuffer ), ]); const [ @@ -3964,6 +4003,12 @@ async function createScaleAdjustPatchReference(params: { targetDraftReference.productLockFalEditMaskBuffer ), ]); + const sourceCropUrl = sourceCropUpload?.url || sourceImageUrl || targetDraftFullUpload?.url; + const targetDraftUrl = + targetDraftUpload?.url || targetDraftFullUpload?.url || sourceImageUrl; + if (!sourceCropUrl || !targetDraftUrl) { + throw new Error("比例调整预处理参考图上传失败,请稍后重试"); + } return { backgroundPlateFullUrl: backgroundPlateFullUpload?.url || null, @@ -3973,10 +4018,10 @@ async function createScaleAdjustPatchReference(params: { productLockFalEditMaskUrl: productLockFalEditMaskUpload?.url || null, productLockOverlayUrl: productLockOverlayUpload?.url || null, productLockProtectMaskUrl: productLockProtectMaskUpload?.url || null, - sourceCropUrl: sourceCropUpload.url, + sourceCropUrl, structureLockedDraft: structureLockAppliedRef.value, - targetDraftFullUrl: targetDraftFullUpload.url, - targetDraftUrl: targetDraftUpload.url, + targetDraftFullUrl: targetDraftFullUpload?.url || sourceImageUrl || null, + targetDraftUrl, workspacePixelRect, workspaceRect, };