Skip to content

Core Concepts

Understanding the building blocks of taskora.

dequeueduesuccesserrorretrybackoffcancelttlWaitingDelayedActiveCompletedFailedRetryingCancelledExpired

Architecture

┌────────────────────────────────────────┐
│  App                                   │
│  ┌──────┐ ┌──────┐ ┌──────┐          │
│  │Task A│ │Task B│ │Task C│  ...      │
│  └──┬───┘ └──┬───┘ └──┬───┘          │
│     │        │        │               │
│     └────────┴────────┘               │
│              │                        │
│        ┌─────┴─────┐                  │
│        │  Adapter   │  ← abstraction  │
│        └─────┬─────┘                  │
│              │                        │
│     ┌────────┴────────┐               │
│     │  Redis / Memory │               │
│     └─────────────────┘               │
└────────────────────────────────────────┘

App

The taskora instance is the central registry. It holds your adapter, serializer, tasks, middleware, schedules, and configuration defaults. You create one per process.

Task

A Task is a named handler with configuration. It defines what happens when a job is processed — plus retry logic, timeout, concurrency, middleware, and more.

Worker

When you call taskora.start(), a Worker is created for each registered task. Workers use blocking dequeue (BZPOPMIN) to efficiently pull jobs from their task's queue — no polling.

Adapter

The Adapter is the storage abstraction layer. The core taskora package never imports ioredis or pg directly. This means:

  • You only install the driver you need
  • Swapping backends requires zero handler changes
  • Testing uses the in-memory adapter — no Docker needed

Job States

A job moves through a well-defined state machine:

StateDescription
waitingQueued, ready to be picked up by a worker
delayedScheduled for future processing (delay or retry backoff)
activeCurrently being processed by a worker
completedHandler returned successfully
failedHandler threw and all retries exhausted
retryingHandler threw but will be retried (moves to delayed)
cancelledExplicitly cancelled via handle.cancel()
expiredTTL exceeded before processing started

State Transitions

dispatch() ──→ waiting ──→ active ──→ completed
                  │           │
           (delay option)     ├──→ failed
                  │           │
                  ▼           ├──→ retrying ──→ delayed ──→ waiting
               delayed        │
                              ├──→ cancelled

                              └──→ expired

Connection Lifecycle

ts
const taskora = createTaskora({ adapter: redisAdapter("redis://localhost:6379") })

// Adapter connects lazily on first dispatch
sendEmailTask.dispatch({ to: "user@example.com", subject: "Hi" })

// Or start workers (connects + starts processing)
await taskora.start()

// Graceful shutdown — finishes active jobs, disconnects
await taskora.close()
Queue 0
Workers 0/3
idle
idle
idle
Done 0

Released under the MIT License.