UNPKG

@sidequest/core

Version:

@sidequest/core is the core package of SideQuest, a distributed background job queue for Node.js and TypeScript applications.

74 lines (70 loc) 2.85 kB
'use strict'; var logger = require('../logger.cjs'); var parseErrorData = require('../tools/parse-error-data.cjs'); var failTransition = require('./fail-transition.cjs'); var transition = require('./transition.cjs'); /** * Transition for retrying a failed job. * * This transition will: * - If the job has reached its maximum attempts, it will mark it as failed. * - If not, it will log the reason for retrying, add the error to the job's errors, * and set the job state to "waiting" with an available_at time * based on an exponential backoff strategy. * - The delay can be specified or calculated using exponential backoff with jitter. * * This transition can only be applied to jobs that are currently running. */ class RetryTransition extends transition.JobTransition { /** Optional delay in milliseconds before retrying. */ delay; /** The reason for retrying. */ reason; /** * Creates a new RetryTransition. * @param reason The reason for retrying. * @param delay Optional delay in milliseconds before retrying. */ constructor(reason, delay) { super(); this.delay = delay; this.reason = reason; } apply(job) { if (job.attempt >= job.max_attempts) { return new failTransition.FailTransition(this.reason).apply(job); } logger.logger("Core").error(this.reason); const reason = parseErrorData.toErrorData(this.reason); const delay = this.delay ?? this.calculateBackoff(job.attempt); logger.logger("Core").info(`Retrying failed job #${job.id} - ${job.class} in ${delay}ms`); const errData = { ...reason, attempt: job.attempt, attempted_at: job.attempted_at, attempt_by: job.claimed_by, }; job.errors ??= []; job.errors.push(errData); job.state = "waiting"; job.available_at = new Date(Date.now() + delay); return job; } /** * Calculates the backoff delay for a retry attempt using exponential backoff with jitter. * * @param attempt - The current retry attempt number (1-based). * @param baseDelay - The base delay in milliseconds for the first attempt. Defaults to 1000 ms. * @param maxDelay - The maximum delay in milliseconds. Defaults to 3,600,000 ms (1 hour). * @returns The calculated backoff delay in milliseconds, randomized with jitter and capped at maxDelay. */ calculateBackoff(attempt, baseDelay = 1000, maxDelay = 3600000) { const jitter = Math.random() + 0.5; return Math.round(Math.min(baseDelay * Math.pow(2, attempt - 1) * jitter, maxDelay)); } shouldRun(job) { return job.state === "running"; } } exports.RetryTransition = RetryTransition; //# sourceMappingURL=retry-transition.cjs.map