feat: Add POST /api/tasks/retry-failed endpoint

Resets failed tasks back to pending for retry.
Options: role (filter), max_age_hours (default 24), limit (default 100)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Kelly
2025-12-13 01:18:07 -07:00
parent 95c23fcdff
commit b1c1955082

View File

@@ -841,6 +841,56 @@ router.post('/recover-stale', async (req: Request, res: Response) => {
}
});
/**
* POST /api/tasks/retry-failed
* Reset failed tasks back to pending for retry
*
* Body:
* - role: string (optional, filter by role)
* - max_age_hours: number (optional, default 24 - only retry tasks from last N hours)
* - limit: number (optional, default 100)
*/
router.post('/retry-failed', async (req: Request, res: Response) => {
try {
const { role, max_age_hours = 24, limit = 100 } = req.body;
let query = `
UPDATE worker_tasks
SET status = 'pending',
worker_id = NULL,
claimed_at = NULL,
started_at = NULL,
completed_at = NULL,
error_message = NULL,
retry_count = retry_count + 1,
updated_at = NOW()
WHERE status = 'failed'
AND created_at > NOW() - INTERVAL '${parseInt(max_age_hours)} hours'
`;
const params: any[] = [];
if (role) {
query += ` AND role = $1`;
params.push(role);
}
query += ` RETURNING id, role, dispensary_id`;
const { rows } = await pool.query(query, params);
console.log(`[Tasks] Retried ${rows.length} failed tasks`);
res.json({
success: true,
tasks_retried: rows.length,
tasks: rows.slice(0, 20), // Return first 20 for visibility
});
} catch (error: unknown) {
console.error('Error retrying failed tasks:', error);
res.status(500).json({ error: 'Failed to retry tasks' });
}
});
/**
* GET /api/tasks/role/:role/last-completion
* Get the last completion time for a role