A tiny, promise-based task queue that runs jobs sequentially with explicit pause/resume and cancellation controls. Designed to keep a single consumer in-order, surface errors deterministically, and make queue status observable for UI or orchestration hooks.
pauseOnError flow that captures the last task error and waits for a resume signalIdle β Processing β Paused/Cancelled)npm install @schie/queue
Requires Node.js 20+.
import { Queue, QueueStatus } from '@schie/queue'
const queue = new Queue({
onStatusChange: (status) => console.log('status:', QueueStatus[status])
})
queue.addTask(async () => {
await doWork('first')
})
queue.addTask(async () => {
await doWork('second')
})
// Pause new work mid-flight
queue.pauseQueue()
setTimeout(() => {
// Clear any previous error and resume processing
queue.resumeQueue()
}, 500)
pauseOnErrorconst queue = new Queue({
onStatusChange: (status) => console.log('status:', QueueStatus[status]),
pauseOnError: true
})
queue.addTask(async () => {
throw new Error('oops')
})
queue.addTask(async () => doWork('after error')) // waits until resume
// When a task fails:
// - status flips to Paused
// - lastTaskError is set
// - processing waits until resumeQueue() is called
if (queue.lastTaskError) {
console.error('last error:', queue.lastTaskError.message)
queue.clearLastError()
queue.resumeQueue()
}
queue.addTask(async () => doWork('maybe cancel me'))
queue.cancelQueue() // clears pending tasks and sets status Cancelled
// Later, adding a task resurrects the queue into a fresh generation
queue.addTask(async () => doWork('fresh start')) // status returns to Idle β Processing
Queue constructortype QueueOptions = {
onStatusChange?: (status: QueueStatus) => void;
pauseOnError?: boolean;
};
new Queue(options?: QueueOptions);
onStatusChange fires only on real status transitions.pauseOnError toggles whether task errors pause the queue and are surfaced via lastTaskError (defaults to false).addTask(task: () => Promise<void>) β enqueue a task; auto-starts if idle and auto-resurrects after cancellation.pauseQueue() β transition to Paused if currently processing.resumeQueue() β clears lastTaskError, transitions back to Processing, and unblocks paused processing. Also restarts if idle with pending work.cancelQueue() β set status to Cancelled, flush pending tasks, and invalidate any in-flight runner.clearQueue() β remove pending tasks; leaves status Idle when not processing/paused/cancelled.clearLastError() β reset lastTaskError without changing status.addNextTask(task: () => Promise<void>) β enqueue a task to run before other pending tasks (after the current in-flight task); auto-starts if idle and auto-resurrects after cancellation.status: QueueStatus β current lifecycle state (Idle, Processing, Paused, Cancelled).isProcessing | isPaused | isCancelled | isIdle β boolean helpers.size: number β pending task count.lastTaskError: Error | null β most recent error when pauseOnError is enabled.Idle.resumeQueue is called.npm test -- --watchman=false β run the Jest suite with coverage (keep it at 100%).npm run build β emit ESM/CJS builds and types.npm run lint β lint the repo (plus lockfile validation).PRs are welcome. Please:
npm scripts instead of bespoke commands.