From e6ba7ad4c1efa09cdd19758c0296e1ea49b50cb8 Mon Sep 17 00:00:00 2001 From: Misaka_Company Date: Fri, 17 Apr 2026 15:39:58 +0800 Subject: [PATCH] fix(cleaner): use copy+unlink for video rename to avoid Windows EBUSY Windows fs.rename fails when ffmpeg still holds the file handle. Use copyFileSync + unlinkSync with retry (up to 10 attempts, 1s interval) to work around the file lock. Co-Authored-By: Claude Opus 4.6 --- src/main/services/erp/cleaner.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/services/erp/cleaner.ts b/src/main/services/erp/cleaner.ts index fe85115..07f507b 100644 --- a/src/main/services/erp/cleaner.ts +++ b/src/main/services/erp/cleaner.ts @@ -1294,8 +1294,24 @@ export class CleanerService { const finalPath = fs.existsSync(orderVideoPath) ? path.join(this.videoDir!, `${expectedOrderNumber}_${Date.now()}${ext}`) : orderVideoPath - fs.renameSync(originalPath, finalPath) - log.debug('[视频录制] 视频已重命名', { from: originalPath, to: finalPath }) + // Copy + unlink instead of rename — Windows EBUSY if ffmpeg still holds the file + await new Promise((resolve, reject) => { + const tryRename = (attempt: number) => { + try { + fs.copyFileSync(originalPath, finalPath) + fs.unlinkSync(originalPath) + log.debug('[视频录制] 视频已重命名', { from: originalPath, to: finalPath }) + resolve() + } catch (err) { + if (attempt < 10) { + setTimeout(() => tryRename(attempt + 1), 1000) + } else { + reject(err) + } + } + } + tryRename(0) + }) } } catch (videoError) { log.warn('[视频录制] 重命名视频失败', {