diff --git a/src/lib/database/models/GenerationResult.ts b/src/lib/database/models/GenerationResult.ts index c6d5a14..fc7d2e6 100644 --- a/src/lib/database/models/GenerationResult.ts +++ b/src/lib/database/models/GenerationResult.ts @@ -86,7 +86,14 @@ export class GenerationResult { expires_at: { $gt: currentTime } }; - return await NeDBManager.update(this.dbName, filterQuery, update, { ...options, multi: false }); + let finalUpdate = update; + // 如果没有操作符,自动包装在 $set 中 + const hasOperators = Object.keys(update).some(key => key.startsWith('$')); + if (!hasOperators) { + finalUpdate = { $set: update }; + } + + return await NeDBManager.update(this.dbName, filterQuery, finalUpdate, { ...options, multi: false }); } // 批量更新结果 @@ -98,7 +105,14 @@ export class GenerationResult { expires_at: { $gt: currentTime } }; - return await NeDBManager.update(this.dbName, filterQuery, update, { ...options, multi: true }); + let finalUpdate = update; + // 如果没有操作符,自动包装在 $set 中 + const hasOperators = Object.keys(update).some(key => key.startsWith('$')); + if (!hasOperators) { + finalUpdate = { $set: update }; + } + + return await NeDBManager.update(this.dbName, filterQuery, finalUpdate, { ...options, multi: true }); } // 删除结果 @@ -116,17 +130,25 @@ export class GenerationResult { const insertedResults: IGenerationResult[] = []; for (const resultData of results) { - const currentTime = Math.floor(Date.now() / 1000); - const result = { - ...resultData, - created_at: resultData.created_at || currentTime, - expires_at: resultData.expires_at || (currentTime + this.DEFAULT_EXPIRY_SECONDS), - is_read: resultData.is_read || false, - read_count: resultData.read_count || 0 - }; - - const insertedResult = await NeDBManager.insert(this.dbName, result); - insertedResults.push(insertedResult); + try { + const currentTime = Math.floor(Date.now() / 1000); + const result = { + ...resultData, + created_at: resultData.created_at || currentTime, + expires_at: resultData.expires_at || (currentTime + this.DEFAULT_EXPIRY_SECONDS), + is_read: resultData.is_read || false, + read_count: resultData.read_count || 0 + }; + + const insertedResult = await NeDBManager.insert(this.dbName, result); + insertedResults.push(insertedResult); + } catch (error) { + // 如果是唯一约束冲突,说明记录已存在,可以忽略 + if (error.message && error.message.includes('unique constraint')) { + continue; + } + throw error; + } } return insertedResults; diff --git a/src/lib/database/models/GenerationTask.ts b/src/lib/database/models/GenerationTask.ts index 16a0fc2..f4b1796 100644 --- a/src/lib/database/models/GenerationTask.ts +++ b/src/lib/database/models/GenerationTask.ts @@ -92,26 +92,44 @@ export class GenerationTask { // 更新任务 static async updateOne(query: any, update: any, options: any = {}): Promise { - // 自动更新 updated_at 时间戳 - if (update.$set) { - update.$set.updated_at = Math.floor(Date.now() / 1000); - } else { - update.updated_at = Math.floor(Date.now() / 1000); + const currentTime = Math.floor(Date.now() / 1000); + let finalUpdate = update; + + // 如果没有操作符,自动包装在 $set 中,防止文档被完全替换 + const hasOperators = Object.keys(update).some(key => key.startsWith('$')); + if (!hasOperators) { + finalUpdate = { $set: update }; } - return await NeDBManager.update(this.dbName, query, update, { ...options, multi: false }); + // 自动更新 updated_at 时间戳 + if (finalUpdate.$set) { + finalUpdate.$set.updated_at = currentTime; + } else { + finalUpdate.$set = { updated_at: currentTime }; + } + + return await NeDBManager.update(this.dbName, query, finalUpdate, { ...options, multi: false }); } // 批量更新任务 static async updateMany(query: any, update: any, options: any = {}): Promise { - // 自动更新 updated_at 时间戳 - if (update.$set) { - update.$set.updated_at = Math.floor(Date.now() / 1000); - } else { - update.updated_at = Math.floor(Date.now() / 1000); + const currentTime = Math.floor(Date.now() / 1000); + let finalUpdate = update; + + // 如果没有操作符,自动包装在 $set 中,防止文档被完全替换 + const hasOperators = Object.keys(update).some(key => key.startsWith('$')); + if (!hasOperators) { + finalUpdate = { $set: update }; } - return await NeDBManager.update(this.dbName, query, update, { ...options, multi: true }); + // 自动更新 updated_at 时间戳 + if (finalUpdate.$set) { + finalUpdate.$set.updated_at = currentTime; + } else { + finalUpdate.$set = { updated_at: currentTime }; + } + + return await NeDBManager.update(this.dbName, query, finalUpdate, { ...options, multi: true }); } // 删除任务 diff --git a/src/lib/services/TaskPollingService.ts b/src/lib/services/TaskPollingService.ts index a9d47c2..452c009 100644 --- a/src/lib/services/TaskPollingService.ts +++ b/src/lib/services/TaskPollingService.ts @@ -396,9 +396,10 @@ export class TaskPollingService { return; } - const { status, fail_code: failCode, fail_msg, item_list } = result[historyId]; - taskLog(`调用即梦API检查结果 ${task.task_id} [status:${status} fail_code: ${failCode} fail_msg: ${fail_msg}]`); - if (status === 20 || status === 45) { + const { status, fail_code: failCode, fail_msg, item_list } = result[historyId]; + let msg = `status:${status} code:${failCode} msg:${fail_msg}`; + taskLog(`调用即梦API检查结果 ${task.task_id} [${msg}]`); + if (status === 20 || status === 42 || status === 45) { // 仍在生成中,更新下次轮询时间 await GenerationTask.updateOne( { task_id: task.task_id }, @@ -409,15 +410,18 @@ export class TaskPollingService { } } ); - } else if (status === 10 || (status !== 30 && item_list && item_list.length > 0)) { + } else if (status === 10 || status === 40) { + //审核失败 可能是敏感信息 + await this.handleGenerationFailure(task, EX.API_CONTENT_FILTERED[1] as string, msg, currentTime); + } else if ((status !== 30 && item_list && item_list.length > 0)) { // 生成完成 await this.handleGenerationSuccess(task, item_list, currentTime); } else { // 生成失败 if(failCode == '2038' || failCode == '2041'){ - await this.handleGenerationFailure(task, EX.API_CONTENT_FILTERED[1] as string, failCode, currentTime); + await this.handleGenerationFailure(task, EX.API_CONTENT_FILTERED[1] as string, msg, currentTime); }else{ - await this.handleGenerationFailure(task, EX.API_IMAGE_GENERATION_FAILED[1] as string, failCode, currentTime); + await this.handleGenerationFailure(task, EX.API_IMAGE_GENERATION_FAILED[1] as string, msg, currentTime); } } @@ -1229,9 +1233,27 @@ export class DatabaseCleanupService { const activeTasks = await GenerationTask.find({ status: { $in: ['processing', 'polling'] } }); + + // 清理由于之前的 bug 导致的损坏数据(缺少 task_id 的任务) + const corruptedTasks = activeTasks.filter(task => !task.task_id); + if (corruptedTasks.length > 0) { + taskLog(`Cleaning up ${corruptedTasks.length} corrupted tasks missing task_id`); + await GenerationTask.deleteMany({ task_id: { $exists: false } }); + // NeDB deleteMany with $exists: false might not work as expected, + // but we can delete them by their NeDB internal _id if needed. + // For now, let's use a more reliable way for NeDB: + for (const task of corruptedTasks) { + if ((task as any)._id) { + await NeDBManager.remove('generation_tasks', { _id: (task as any)._id }); + } + } + } // 在内存中过滤超时任务(NeDB 不支持 $expr) const timeoutTasks = activeTasks.filter(task => { + // 确保任务有有效 ID + if (!task.task_id) return false; + const elapsedTime = currentTime - (task.started_at || task.created_at); return elapsedTime > (task.task_timeout || 3600); // 默认1小时超时 }); @@ -1243,10 +1265,12 @@ export class DatabaseCleanupService { await GenerationTask.updateMany( { task_id: { $in: timeoutTaskIds } }, { - status: 'failed', - error_message: 'Task timeout', - updated_at: currentTime, - completed_at: currentTime + $set: { + status: 'failed', + error_message: 'Task timeout', + updated_at: currentTime, + completed_at: currentTime + } } ); @@ -1261,7 +1285,7 @@ export class DatabaseCleanupService { metadata: { total_files: 0, successful_uploads: 0, - fail_reason: 'Task timeout after ' + task.task_timeout + ' seconds' + fail_reason: 'Task timeout after ' + (task.task_timeout || 3600) + ' seconds' }, created_at: currentTime, expires_at: currentTime + parseInt(process.env.RESULT_EXPIRE_TIME || '86400'), @@ -1270,7 +1294,17 @@ export class DatabaseCleanupService { })); if (failedResults.length > 0) { - await GenerationResult.insertMany(failedResults); + // 逐个插入以防个别任务已存在导致整体失败 + for (const result of failedResults) { + try { + await GenerationResult.create(result); + } catch (e) { + // 忽略重复记录或其他插入错误,避免中断清理流程 + if (!e.message.includes('unique constraint')) { + taskLog(`Failed to create timeout result for ${result.task_id}: ${e.message}`); + } + } + } } }