queue-tea
Version:
A simple, robust, persistable job & task queue written in typescript. Full type safety included.
127 lines (121 loc) • 3 kB
JavaScript
// 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
};