Protect upload cleanup and atomic completion paths, add durable media worker leases and brand asset validation, and introduce verified migration/bootstrap/deployment gates.
48 lines
2.0 KiB
TypeScript
48 lines
2.0 KiB
TypeScript
import { prisma } from '@/lib/prisma'
|
||
|
||
export type TaskMaterialCompletionState =
|
||
| { state: 'completed'; taskStatus: 'completed'; previewUrl: string; zipFilePath: string }
|
||
| { state: 'completed_incomplete'; taskStatus: 'completed'; previewUrl: string; zipFilePath: string }
|
||
| { state: 'processing'; taskStatus: 'processing' }
|
||
| { state: 'other'; taskStatus: string | null | undefined }
|
||
| { state: 'unknown'; error: unknown }
|
||
|
||
/**
|
||
* 完成接口遇到数据库异常时,不能凭本地布尔值判断事务是否提交。
|
||
* 只有再次确认仍是 processing,调用方才可以删除本请求产物;查询失败时必须
|
||
* 保留全部文件,交给重试/人工核查,避免“记录 completed、文件却被回滚”。
|
||
*/
|
||
export async function inspectTaskMaterialCompletionAfterError(
|
||
materialId: string,
|
||
): Promise<TaskMaterialCompletionState> {
|
||
try {
|
||
const material = await prisma.material.findUnique({
|
||
where: { id: materialId },
|
||
select: {
|
||
taskStatus: true,
|
||
previewUrl: true,
|
||
zipFilePath: true,
|
||
assets: {
|
||
where: { assetType: { in: ['preview', 'zip'] } },
|
||
select: { assetType: true },
|
||
},
|
||
},
|
||
})
|
||
if (material?.taskStatus === 'completed') {
|
||
const previewUrl = String(material.previewUrl || '').trim()
|
||
const zipFilePath = String(material.zipFilePath || '').trim()
|
||
const assetTypes = new Set(material.assets.map((asset) => asset.assetType))
|
||
if (previewUrl && zipFilePath && assetTypes.has('preview') && assetTypes.has('zip')) {
|
||
return { state: 'completed', taskStatus: 'completed', previewUrl, zipFilePath }
|
||
}
|
||
return { state: 'completed_incomplete', taskStatus: 'completed', previewUrl, zipFilePath }
|
||
}
|
||
if (material?.taskStatus === 'processing') {
|
||
return { state: 'processing', taskStatus: 'processing' }
|
||
}
|
||
return { state: 'other', taskStatus: material?.taskStatus }
|
||
} catch (error) {
|
||
return { state: 'unknown', error }
|
||
}
|
||
}
|