feat(video-from-script): 区分视频生成超时与任务失败,保留 taskId 支持恢复
核心改动:将超时与任务失败明确区分,超时场景保留 taskId 和 pending 状态, 等待下次恢复,避免重复计费;仅 API 明确返回 failed 时才清理 taskId 并重试。 - phase-videos.js: 恢复失败分超时/失败处理,超时保留 taskId 置 pending - phase-videos.js: 轮询结果超时也保留 taskId 存 pending - video-poll-utils.js: 增加 isTaskFailed 判断;超时禁止创建新任务 - video-poll-utils.js: 提升轮询重试次数至 5 次以允许超时等待
This commit is contained in:
@@ -44,7 +44,7 @@ async function phaseVideos(manifest, manifestPath, options) {
|
||||
console.log()
|
||||
}
|
||||
|
||||
// 已有视频(本地或 OSS)且状态为 done 的跳过,其余清理后重新生成
|
||||
// 已有视频(本地或 OSS)且状态为 done 的跳过,其余清理视频引用但保留 taskId 供恢复
|
||||
const items = []
|
||||
for (const it of videoCandidates) {
|
||||
if (it.video || it.videoUrl) {
|
||||
@@ -52,7 +52,6 @@ async function phaseVideos(manifest, manifestPath, options) {
|
||||
delete it.video
|
||||
delete it.videoUrl
|
||||
delete it.videoDuration
|
||||
delete it.videoTaskId
|
||||
}
|
||||
items.push(it)
|
||||
}
|
||||
@@ -107,9 +106,15 @@ async function phaseVideos(manifest, manifestPath, options) {
|
||||
log('videos', ` item ${item.id} 恢复成功`)
|
||||
}
|
||||
} catch (err) {
|
||||
log('videos', ` item ${item.id} 恢复失败: ${err.message},将重新提交`)
|
||||
delete item.videoTaskId
|
||||
needSubmit.push(item)
|
||||
const isFail = err.isTaskFailure === true
|
||||
if (isFail) {
|
||||
log('videos', ` item ${item.id} 恢复失败(任务失败): ${err.message},将重新提交`)
|
||||
delete item.videoTaskId
|
||||
needSubmit.push(item)
|
||||
} else {
|
||||
log('videos', ` item ${item.id} 恢复超时(保留 taskId 下次重试): ${err.message}`)
|
||||
item.status = 'pending'
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
@@ -172,25 +177,32 @@ async function phaseVideos(manifest, manifestPath, options) {
|
||||
})
|
||||
return { item, result, ok: true }
|
||||
} catch (err) {
|
||||
return { item, error: err.message, ok: false }
|
||||
return { item, error: err.message, ok: false, isTaskFailure: err.isTaskFailure === true }
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
for (const r of pollResults) {
|
||||
const val = r.status === 'fulfilled' ? r.value : { ok: false, error: r.reason?.message }
|
||||
const val = r.status === 'fulfilled'
|
||||
? r.value
|
||||
: { ok: false, error: r.reason?.message || String(r.reason), isTaskFailure: r.reason?.isTaskFailure === true }
|
||||
if (val.ok && val.result.file) {
|
||||
val.item.video = path.relative(dir, val.result.file).replace(/\\/g, '/')
|
||||
val.item.videoDuration = val.result.duration
|
||||
val.item.status = 'done'
|
||||
delete val.item.videoTaskId
|
||||
} else if (val.item) {
|
||||
val.item.status = 'failed'
|
||||
val.item.error = val.error || '视频生成未返回文件'
|
||||
delete val.item.videoTaskId
|
||||
if (val.isTaskFailure) {
|
||||
val.item.status = 'failed'
|
||||
val.item.error = val.error || '视频生成未返回文件'
|
||||
delete val.item.videoTaskId
|
||||
} else {
|
||||
log('videos', ` item ${val.item.id} 生成超时(保留 taskId 待恢复): ${val.error}`)
|
||||
val.item.status = 'pending'
|
||||
}
|
||||
}
|
||||
saveManifest(manifestPath, manifest)
|
||||
}
|
||||
saveManifest(manifestPath, manifest)
|
||||
|
||||
// 上传视频到 OSS
|
||||
const { uploadFile } = require('../oss-upload')
|
||||
|
||||
Reference in New Issue
Block a user