Protect upload cleanup and atomic completion paths, add durable media worker leases and brand asset validation, and introduce verified migration/bootstrap/deployment gates.
67 lines
2.8 KiB
TypeScript
67 lines
2.8 KiB
TypeScript
/**
|
||
* Next.js Instrumentation
|
||
*
|
||
* 这个文件在应用启动时执行,用于:
|
||
* 1. 启动临时文件定时清理任务
|
||
* 2. 初始化其他需要在启动时运行的服务
|
||
*/
|
||
|
||
export async function register() {
|
||
// 只在 Node.js 服务端运行(不在 Edge 运行时)
|
||
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
||
console.log('[Instrumentation] Next.js 服务端启动...')
|
||
|
||
// 启动临时文件清理任务
|
||
try {
|
||
const { startCleanupScheduler } = await import('./lib/temp-cleanup')
|
||
startCleanupScheduler()
|
||
console.log('[Instrumentation] 临时文件清理任务已启动')
|
||
} catch (error) {
|
||
console.error('[Instrumentation] 启动清理任务失败:', error)
|
||
}
|
||
|
||
const recoveryGlobal = globalThis as typeof globalThis & {
|
||
__taskDetailUploadRecoveryStarted?: boolean
|
||
}
|
||
if (!recoveryGlobal.__taskDetailUploadRecoveryStarted) {
|
||
recoveryGlobal.__taskDetailUploadRecoveryStarted = true
|
||
// 先注册周期任务,再做首次恢复。数据库启动瞬时不可用时,后续周期仍会重试,
|
||
// 不会因为一次失败让 processing/queued 任务永久无人处理。
|
||
setInterval(() => {
|
||
void import('./lib/task-detail-upload-jobs')
|
||
.then(({ recoverTaskDetailUploadJobs }) => recoverTaskDetailUploadJobs())
|
||
.catch((error) => {
|
||
console.error('[Instrumentation] 任务-详情后台队列周期恢复失败:', error)
|
||
})
|
||
}, 60_000)
|
||
}
|
||
|
||
try {
|
||
const { recoverTaskDetailUploadJobs } = await import('./lib/task-detail-upload-jobs')
|
||
await recoverTaskDetailUploadJobs()
|
||
console.log('[Instrumentation] 任务-详情后台队列恢复检查完成')
|
||
} catch (error) {
|
||
// 迁移未执行或数据库暂不可用时只记录;周期恢复已提前注册,会继续重试。
|
||
console.error('[Instrumentation] 任务-详情后台队列恢复失败:', error)
|
||
}
|
||
|
||
const videoRecoveryGlobal = globalThis as typeof globalThis & {
|
||
__videoTranscodeRecoveryScheduler?: {
|
||
initial: Promise<number>
|
||
}
|
||
}
|
||
if (!videoRecoveryGlobal.__videoTranscodeRecoveryScheduler) {
|
||
const { createVideoTranscodeRecoveryScheduler } = await import('./lib/video-transcode-recovery')
|
||
const scheduler = createVideoTranscodeRecoveryScheduler()
|
||
videoRecoveryGlobal.__videoTranscodeRecoveryScheduler = scheduler
|
||
try {
|
||
const recovered = await scheduler.initial
|
||
console.log(`[Instrumentation] 视频转码启动恢复完成,重新入队 ${recovered} 个任务`)
|
||
} catch (error) {
|
||
// 周期调度器已先注册;数据库瞬时不可用时,60 秒后会继续重试。
|
||
console.error('[Instrumentation] 视频转码启动恢复失败,已保留周期重试:', error)
|
||
}
|
||
}
|
||
}
|
||
}
|