UNPKG

queue-manager-pro

Version:

A flexible, TypeScript-first queue/task manager with pluggable backends ,dynamic persistence storage and event hooks.

78 lines 3.1 kB
import { randomUUID } from 'crypto'; export class BaseQueueRepository { logger; emitEvent; MAX_RETRIES; MAX_PROCESSING_TIME; id; dequeueLock = false; constructor(maxRetries, maxProcessingTime) { this.MAX_RETRIES = maxRetries; this.MAX_PROCESSING_TIME = maxProcessingTime; this.id = randomUUID(); } // same for in-memory and file repositories, others will be overridden async updateTask(id, obj) { const tasks = await this.loadTasks(); const task = tasks.find(t => t.id === id); if (task) { Object.assign(task, obj); task.updatedAt = new Date(); await this.saveTasks(tasks); return task; } return undefined; } sortTasksToDequeue(taskA, taskB) { return taskB.priority - taskA.priority || new Date(taskA.createdAt).getTime() - new Date(taskB.createdAt).getTime(); } // same for in-memory and file repositories, others will be overridden async dequeue() { if (this.dequeueLock) return null; this.dequeueLock = true; try { const tasks = await this.loadTasks(); const taskToProcess = [...tasks].sort(this.sortTasksToDequeue).find(t => t.status === 'pending'); if (taskToProcess) { taskToProcess.status = 'processing'; await this.saveTasks(tasks); return taskToProcess; } else { await this.checkAndHandleStuckTasks(tasks); return null; } } finally { this.dequeueLock = false; } } async checkAndHandleStuckTasks(tasks) { const now = Date.now(); for (const task of tasks) { if (task.status !== 'processing') continue; const elapsed = now - new Date(task.updatedAt).getTime(); this.logger?.info(`Checking task ${task.id} status: elapsed time ${elapsed / 1000}s`); const maxProcessingTime = task.maxProcessingTime ?? this.MAX_PROCESSING_TIME; if (elapsed > maxProcessingTime) { this.emitEvent?.('taskStuck', task); this.logger?.warn(`Task ${task.id} is stuck`); const maxRetries = task.maxRetries ?? this.MAX_RETRIES; if (task?.retryCount < maxRetries) { this.logger?.warn(`Retrying task ${task.id} (${task.retryCount + 1}/${maxRetries})`); await this.updateTask(task.id, { retryCount: task.retryCount + 1, status: 'pending' }); this.emitEvent?.('taskRetried', task); } else { const error = `Task ${task.id} failed after ${maxRetries} retries`; this.emitEvent?.('taskFailed', task, new Error(error)); this.logger?.error(error); await this.updateTask(task.id, { status: 'failed' }); } } } } } //# sourceMappingURL=base.repository.js.map