This commit is contained in:
jonathang4 2025-12-24 11:22:40 +08:00
parent 3569981edc
commit 8ab4af3ec4
3 changed files with 111 additions and 37 deletions

View File

@ -86,7 +86,14 @@ export class GenerationResult {
expires_at: { $gt: currentTime } 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 } 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,6 +130,7 @@ export class GenerationResult {
const insertedResults: IGenerationResult[] = []; const insertedResults: IGenerationResult[] = [];
for (const resultData of results) { for (const resultData of results) {
try {
const currentTime = Math.floor(Date.now() / 1000); const currentTime = Math.floor(Date.now() / 1000);
const result = { const result = {
...resultData, ...resultData,
@ -127,6 +142,13 @@ export class GenerationResult {
const insertedResult = await NeDBManager.insert(this.dbName, result); const insertedResult = await NeDBManager.insert(this.dbName, result);
insertedResults.push(insertedResult); insertedResults.push(insertedResult);
} catch (error) {
// 如果是唯一约束冲突,说明记录已存在,可以忽略
if (error.message && error.message.includes('unique constraint')) {
continue;
}
throw error;
}
} }
return insertedResults; return insertedResults;

View File

@ -92,26 +92,44 @@ export class GenerationTask {
// 更新任务 // 更新任务
static async updateOne(query: any, update: any, options: any = {}): Promise<number> { static async updateOne(query: any, update: any, options: any = {}): Promise<number> {
// 自动更新 updated_at 时间戳 const currentTime = Math.floor(Date.now() / 1000);
if (update.$set) { let finalUpdate = update;
update.$set.updated_at = Math.floor(Date.now() / 1000);
} else { // 如果没有操作符,自动包装在 $set 中,防止文档被完全替换
update.updated_at = Math.floor(Date.now() / 1000); 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<number> { static async updateMany(query: any, update: any, options: any = {}): Promise<number> {
// 自动更新 updated_at 时间戳 const currentTime = Math.floor(Date.now() / 1000);
if (update.$set) { let finalUpdate = update;
update.$set.updated_at = Math.floor(Date.now() / 1000);
} else { // 如果没有操作符,自动包装在 $set 中,防止文档被完全替换
update.updated_at = Math.floor(Date.now() / 1000); 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 });
} }
// 删除任务 // 删除任务

View File

@ -397,8 +397,9 @@ export class TaskPollingService {
} }
const { status, fail_code: failCode, fail_msg, item_list } = result[historyId]; 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}]`); let msg = `status:${status} code:${failCode} msg:${fail_msg}`;
if (status === 20 || status === 45) { taskLog(`调用即梦API检查结果 ${task.task_id} [${msg}]`);
if (status === 20 || status === 42 || status === 45) {
// 仍在生成中,更新下次轮询时间 // 仍在生成中,更新下次轮询时间
await GenerationTask.updateOne( await GenerationTask.updateOne(
{ task_id: task.task_id }, { 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); await this.handleGenerationSuccess(task, item_list, currentTime);
} else { } else {
// 生成失败 // 生成失败
if(failCode == '2038' || failCode == '2041'){ 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{ }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);
} }
} }
@ -1230,8 +1234,26 @@ export class DatabaseCleanupService {
status: { $in: ['processing', 'polling'] } 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 // 在内存中过滤超时任务NeDB 不支持 $expr
const timeoutTasks = activeTasks.filter(task => { const timeoutTasks = activeTasks.filter(task => {
// 确保任务有有效 ID
if (!task.task_id) return false;
const elapsedTime = currentTime - (task.started_at || task.created_at); const elapsedTime = currentTime - (task.started_at || task.created_at);
return elapsedTime > (task.task_timeout || 3600); // 默认1小时超时 return elapsedTime > (task.task_timeout || 3600); // 默认1小时超时
}); });
@ -1243,11 +1265,13 @@ export class DatabaseCleanupService {
await GenerationTask.updateMany( await GenerationTask.updateMany(
{ task_id: { $in: timeoutTaskIds } }, { task_id: { $in: timeoutTaskIds } },
{ {
$set: {
status: 'failed', status: 'failed',
error_message: 'Task timeout', error_message: 'Task timeout',
updated_at: currentTime, updated_at: currentTime,
completed_at: currentTime completed_at: currentTime
} }
}
); );
// 为超时任务创建失败结果记录 // 为超时任务创建失败结果记录
@ -1261,7 +1285,7 @@ export class DatabaseCleanupService {
metadata: { metadata: {
total_files: 0, total_files: 0,
successful_uploads: 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, created_at: currentTime,
expires_at: currentTime + parseInt(process.env.RESULT_EXPIRE_TIME || '86400'), expires_at: currentTime + parseInt(process.env.RESULT_EXPIRE_TIME || '86400'),
@ -1270,7 +1294,17 @@ export class DatabaseCleanupService {
})); }));
if (failedResults.length > 0) { 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}`);
}
}
}
} }
} }