feat: migrate task jobs to workflow notifications + timeline
This commit is contained in:
@@ -1,41 +1,48 @@
|
||||
import { sleep } from 'workflow';
|
||||
import { start } from 'workflow/api';
|
||||
import { runTaskProcessor } from '@/lib/server/task-processors';
|
||||
import {
|
||||
claimQueuedTask,
|
||||
completeTask,
|
||||
markTaskFailure
|
||||
getTaskById,
|
||||
markTaskFailure,
|
||||
markTaskRunning
|
||||
} from '@/lib/server/repos/tasks';
|
||||
import type { Task } from '@/lib/types';
|
||||
|
||||
export async function runTaskWorkflow(taskId: string) {
|
||||
'use workflow';
|
||||
|
||||
const task = await claimQueuedTaskStep(taskId);
|
||||
const task = await loadTaskStep(taskId);
|
||||
if (!task) {
|
||||
return;
|
||||
}
|
||||
|
||||
await markTaskRunningStep(task.id);
|
||||
|
||||
try {
|
||||
const result = await processTaskStep(task);
|
||||
const refreshedTask = await loadTaskStep(task.id);
|
||||
if (!refreshedTask) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await processTaskStep(refreshedTask);
|
||||
await completeTaskStep(task.id, result);
|
||||
} catch (error) {
|
||||
const reason = error instanceof Error
|
||||
? error.message
|
||||
: 'Task failed unexpectedly';
|
||||
|
||||
const nextState = await markTaskFailureStep(task.id, reason);
|
||||
|
||||
if (nextState.shouldRetry) {
|
||||
await sleep('1200ms');
|
||||
await restartTaskWorkflowStep(task.id);
|
||||
}
|
||||
await markTaskFailureStep(task.id, reason);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function claimQueuedTaskStep(taskId: string) {
|
||||
async function loadTaskStep(taskId: string) {
|
||||
'use step';
|
||||
return await claimQueuedTask(taskId);
|
||||
return await getTaskById(taskId);
|
||||
}
|
||||
|
||||
async function markTaskRunningStep(taskId: string) {
|
||||
'use step';
|
||||
await markTaskRunning(taskId);
|
||||
}
|
||||
|
||||
async function processTaskStep(task: Task) {
|
||||
@@ -43,7 +50,7 @@ async function processTaskStep(task: Task) {
|
||||
return await runTaskProcessor(task);
|
||||
}
|
||||
|
||||
// Step-level retries duplicate task-level retry handling and can create noisy AI failure loops.
|
||||
// Keep retries at the projection workflow level to avoid duplicate side effects.
|
||||
(
|
||||
processTaskStep as ((task: Task) => Promise<Record<string, unknown>>) & { maxRetries?: number }
|
||||
).maxRetries = 0;
|
||||
@@ -55,10 +62,5 @@ async function completeTaskStep(taskId: string, result: Record<string, unknown>)
|
||||
|
||||
async function markTaskFailureStep(taskId: string, reason: string) {
|
||||
'use step';
|
||||
return await markTaskFailure(taskId, reason);
|
||||
}
|
||||
|
||||
async function restartTaskWorkflowStep(taskId: string) {
|
||||
'use step';
|
||||
await start(runTaskWorkflow, [taskId]);
|
||||
await markTaskFailure(taskId, reason);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user