import { query } from '../db/client.js'; export type TaskStatus = 'pending' | 'running' | 'completed' | 'failed'; export type TaskType = 'predict_page' | 'predict_all' | 'predict_custom'; export interface Task { id: string; score_id: string; type: TaskType; status: TaskStatus; progress: number; current_step: string | null; result: Record | null; error: string | null; created_at: Date; started_at: Date | null; completed_at: Date | null; } export interface CreateTaskInput { score_id: string; type: TaskType; } export async function createTask(input: CreateTaskInput): Promise { const { rows } = await query( `INSERT INTO tasks (score_id, type) VALUES ($1, $2) RETURNING *`, [input.score_id, input.type] ); return rows[0]; } export async function getTask(id: string): Promise { const { rows } = await query('SELECT * FROM tasks WHERE id = $1', [id]); return rows[0] || null; } export async function listTasks(scoreId?: string, status?: TaskStatus): Promise { let sql = 'SELECT * FROM tasks'; const conditions: string[] = []; const values: any[] = []; let paramIndex = 1; if (scoreId) { conditions.push(`score_id = $${paramIndex++}`); values.push(scoreId); } if (status) { conditions.push(`status = $${paramIndex++}`); values.push(status); } if (conditions.length > 0) { sql += ' WHERE ' + conditions.join(' AND '); } sql += ' ORDER BY created_at DESC'; const { rows } = await query(sql, values); return rows; } export async function updateTaskStatus(id: string, status: TaskStatus, progress?: number, currentStep?: string): Promise { const updates: string[] = ['status = $2']; const values: any[] = [id, status]; let paramIndex = 3; if (progress !== undefined) { updates.push(`progress = $${paramIndex++}`); values.push(progress); } if (currentStep !== undefined) { updates.push(`current_step = $${paramIndex++}`); values.push(currentStep); } if (status === 'running') { updates.push('started_at = NOW()'); } else if (status === 'completed' || status === 'failed') { updates.push('completed_at = NOW()'); } const { rows } = await query(`UPDATE tasks SET ${updates.join(', ')} WHERE id = $1 RETURNING *`, values); return rows[0] || null; } export async function setTaskResult(id: string, result: Record): Promise { const { rows } = await query( `UPDATE tasks SET result = $2, status = 'completed', progress = 100, completed_at = NOW() WHERE id = $1 RETURNING *`, [id, JSON.stringify(result)] ); return rows[0] || null; } export async function setTaskError(id: string, error: string): Promise { const { rows } = await query( `UPDATE tasks SET error = $2, status = 'failed', completed_at = NOW() WHERE id = $1 RETURNING *`, [id, error] ); return rows[0] || null; } export async function getPendingTasks(limit = 10): Promise { const { rows } = await query(`SELECT * FROM tasks WHERE status = 'pending' ORDER BY created_at LIMIT $1`, [limit]); return rows; } export async function claimTask(id: string): Promise { // Atomic update to prevent race conditions const { rows } = await query( `UPDATE tasks SET status = 'running', started_at = NOW() WHERE id = $1 AND status = 'pending' RETURNING *`, [id] ); return rows[0] || null; }