An open API service indexing awesome lists of open source software.

https://github.com/schie/queue

A simple task queue implementation in TypeScript.
https://github.com/schie/queue

queue typescript

Last synced: 5 months ago
JSON representation

A simple task queue implementation in TypeScript.

Awesome Lists containing this project

README

          

# @schie/queue

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.

## Features

- βœ… Single runner, in-order task execution (no accidental parallelism)
- ⏸️ Explicit pause/resume with backpressure-friendly blocking
- πŸ›‘ Cancellation that flushes pending work and blocks stale generations from changing state
- 🚨 Optional `pauseOnError` flow that captures the last task error and waits for a resume signal
- πŸ•ΉοΈ Status callbacks for wiring into logs, metrics, or UI (`Idle` β†’ `Processing` β†’ `Paused/Cancelled`)
- πŸ“¦ Zero dependencies, ESM + CJS builds, typed with TypeScript

## Installation

```bash
npm install @schie/queue
```

Requires Node.js 20+.

## Quick Start

```typescript
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)
```

### Handling errors with `pauseOnError`

```typescript
const 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()
}
```

### Cancellation and auto-resurrection

```typescript
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
```

## API

### `Queue` constructor

```typescript
type 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`).

### Methods

- `addTask(task: () => Promise, dedupeKey?: string)` β€” enqueue a task; if `dedupeKey` matches the last pending task key, skip enqueueing; 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)` β€” enqueue a task to run before other pending tasks (after the current in-flight task); auto-starts if idle and auto-resurrects after cancellation.

### Properties

- `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.

### Invariants and behavior

- Single runner: tasks execute sequentially; the queue never introduces parallelism.
- Generation guard: cancellation increments an internal version so stale runners cannot revert status later.
- Draining: when the queue empties (and not cancelled), status returns to `Idle`.
- Pausing: while paused, processing blocks until `resumeQueue` is called.

## Scripts and Testing

- `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).

## Contributing

PRs are welcome. Please:

- Keep behavior changes aligned with the TypeScript source and this README.
- Preserve the single-consumer, in-order contract and status integrity.
- Add or update tests to maintain 100% coverage.
- Use the provided `npm` scripts instead of bespoke commands.