import dbHandler from "../db-handler"; import { quoteIdentifier } from "../../utils/sql-identifier"; import { QUEUE_NOW_SQL, requireQueueTable } from "./queue-utils"; /** * Release a claimed job after a failed attempt. It goes back to `pending` * (after `retry_delay_ms`) or to `failed` once `max_attempts` is reached. */ export default async function QueueFail({ table, id, lock_token, error, retry_delay_ms = 0, max_attempts, config, }) { try { const options = requireQueueTable(table); const tableSql = quoteIdentifier(table); const retryDelayMs = Math.max(0, Math.floor(Number(retry_delay_ms) || 0)); const maxAttempts = Math.max(1, Math.floor(Number(max_attempts ?? options.max_attempts) || 1)); const res = await dbHandler({ query: `UPDATE ${tableSql} SET queue_status = IF(queue_attempts >= ?, 'failed', 'pending'), queue_available_at = ${QUEUE_NOW_SQL} + ?, queue_lease_expires_at = NULL, queue_lock_token = NULL, queue_last_error = ?, updated_at = ${QUEUE_NOW_SQL} WHERE id = ? AND queue_status = 'processing' AND queue_lock_token = ?`, values: [maxAttempts, retryDelayMs, error ?? null, id, lock_token], config, }); if (!res.success) { return { ...res, success: false }; } if (!res.db_res?.affectedRows) { return { ...res, success: false, msg: "Job is not claimed with this lock token", }; } return await dbHandler({ query: `SELECT * FROM ${quoteIdentifier(table)} WHERE id = ?`, values: [id], config, }); } catch (error) { return { success: false, error: error.message, }; } }