UNPKG

node-downloader-manager

Version:

node-downloader-manager is a simple yet powerful package manager-like download manager built with NodeJs. It allows you to download files sequentially or with a queue-based approach, handling retries and concurrency limits efficiently.

105 lines (104 loc) 3.59 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); class Queue { heap = []; activeCount = 0; concurrencyLimit; maxRetries; log; backOff; constructor(concurrencyLimit, maxRetries, consoleLog, backOff = false) { this.concurrencyLimit = concurrencyLimit; this.maxRetries = maxRetries; this.log = consoleLog; this.backOff = backOff; } logger(message, type = "info") { if (this.log) { console[type](`[${process.pid}] : [${new Date().toLocaleString()}] : `, message); } } calculateBackoff(attempt) { const baseDelay = 1000; const maxDelay = 30000; return Math.min(baseDelay * 2 ** attempt, maxDelay); } heapifyUp(index) { const task = this.heap[index]; while (index > 0) { const parentIndex = Math.floor((index - 1) / 2); if (parentIndex < 0 || parentIndex >= this.heap.length) break; if (this.heap[parentIndex] && this.heap[parentIndex].priority >= task.priority) break; this.heap[index] = this.heap[parentIndex]; index = parentIndex; } this.heap[index] = task; } enqueue(task) { this.heap.push(task); this.heapifyUp(this.heap.length - 1); this.runNext(); } heapifyDown(index) { const length = this.heap.length; while (true) { const leftChildIndex = 2 * index + 1; const rightChildIndex = 2 * index + 2; let largestIndex = index; if (leftChildIndex < length && this.heap[leftChildIndex].priority > this.heap[largestIndex].priority) { largestIndex = leftChildIndex; } if (rightChildIndex < length && this.heap[rightChildIndex].priority > this.heap[largestIndex].priority) { largestIndex = rightChildIndex; } if (largestIndex === index) break; [this.heap[index], this.heap[largestIndex]] = [ this.heap[largestIndex], this.heap[index], ]; index = largestIndex; } } async runNext() { if (this.activeCount >= this.concurrencyLimit || this.heap.length === 0) { return; } const task = this.heap[0]; if (!task) return; this.heap[0] = this.heap[this.heap.length - 1]; this.heap.pop(); this.heapifyDown(0); this.activeCount++; try { await task.action(); this.logger(`Task ${task.id} completed successfully.`); } catch (err) { this.logger(`Task ${task.id} failed: ${err}`, "error"); if (task.retries < this.maxRetries) { this.logger(`Retrying task ${task.id}...`); if (this.backOff) { const backoffDelay = this.calculateBackoff(task.retries); this.logger(`Task ${task.id} - Retrying in ${backoffDelay / 1000} seconds...`); await new Promise((resolve) => setTimeout(resolve, backoffDelay)); } this.enqueue({ ...task, retries: task.retries + 1 }); } else { this.logger(`Task ${task.id} exceeded max retries.`, "warn"); } } finally { this.activeCount--; this.runNext(); } } } exports.default = Queue;