UNPKG

queue-tea

Version:

A simple, robust, persistable job & task queue written in typescript. Full type safety included.

127 lines (121 loc) 3 kB
// src/TaskQueue.ts import { createNanoEvents } from "nanoevents"; // src/Queue.ts var Queue = class { constructor(elements) { this.tasks = []; this.enqueue = (e) => { this.tasks = [...this.tasks, e]; }; this.dequeue = () => { const task = this.peek(); this.tasks = this.tasks.slice(1); return task; }; this.isEmpty = () => { return this.tasks.length === 0; }; this.peek = () => { return !this.isEmpty() ? this.tasks[0] : void 0; }; this.length = () => { return this.tasks.length; }; this.tasks = elements; } }; // src/utils/sleep.ts var sleep = (delay) => new Promise((res) => setTimeout(res, delay)); // src/utils/uuid.ts var uuid = () => "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { const r = Math.random() * 16 | 0; return (c === "x" ? r : r & 3 | 8).toString(16); }); // src/TaskQueue.ts var defaultCalculateBackoff = (retryCount) => { const noise = Math.random() * 100; return Math.min(retryCount * 1e3, 5e3) + noise; }; var TaskQueue = ({ initialState = [], tasks, onChange, retryDelay = defaultCalculateBackoff }) => { const events = createNanoEvents(); const queuedTasks = new Queue(initialState); let state = "paused"; const queueTask = (name, ...options) => { const id = uuid(); queuedTasks.enqueue({ id, name, retries: 0, options: options[0], createdAt: Date.now() }); if (state === "idle") { run(); } const task = new Promise((res, rej) => { events.on("success", (task2) => { if (task2.id === id) { res(); } events.on("fail", (task3, error) => { if (task3.id === id) { rej(error); } }); }); }); return { id, task }; }; const pause = () => { state = "paused"; }; const isPaused = () => state === "paused"; const run = async () => { state = "running"; while (!queuedTasks.isEmpty()) { if (isPaused()) { break; } const task = queuedTasks.peek(); if (!task) { break; } try { await tasks[task.name](task.options, { createdAt: task.createdAt, retries: task.retries }); queuedTasks.dequeue(); onChange == null ? void 0 : onChange(queuedTasks.tasks); events.emit("success", task); } catch (e) { events.emit("fail", task, e); await sleep(retryDelay(++task.retries)); } finally { events.emit("change", { tasks: [...queuedTasks.tasks], remainingTasks: queuedTasks.length() }); } } state = "idle"; }; return { run, getState: () => state, pause, getQueueItems: () => [...queuedTasks.tasks], addEventListener: (event, callback) => events.on(event, callback), queueTask }; }; // src/index.ts var src_default = TaskQueue; export { src_default as default };