Skip to content

Priority and Ordering

Conveyor supports job prioritization and FIFO/LIFO ordering. Priority determines which waiting jobs are fetched first, while LIFO inverts the default first-in-first-out order.

Quick Examples

Priority

Lower numbers mean higher priority:

typescript
import { Queue, Worker } from '@conveyor/core';

const queue = new Queue('tasks', { store });

// High priority (processed first)
await queue.add('urgent', payload, { priority: 1 });

// Normal priority
await queue.add('standard', payload, { priority: 10 });

// Low priority (processed last)
await queue.add('background', payload, { priority: 100 });

// Default priority is 0 (highest)
await queue.add('default-priority', payload);

LIFO (Last In, First Out)

Process the most recently added job first:

typescript
// Per-job LIFO
await queue.add('task-a', payload);
await queue.add('task-b', payload, { lifo: true }); // fetched before task-a

// Per-worker LIFO (applies to all fetches)
const worker = new Worker('tasks', handler, {
  store,
  lifo: true,
});

Combined Priority and LIFO

typescript
// Priority takes precedence over LIFO/FIFO within the same priority level
await queue.add('low', payloadA, { priority: 10 });
await queue.add('high', payloadB, { priority: 1 });
await queue.add('high-2', payloadC, { priority: 1 });

// Processing order: high, high-2, low (by priority, then FIFO within same priority)

Configuration Options

JobOptions

OptionTypeDefaultDescription
prioritynumber0Lower number = higher priority
lifobooleanfalseLast-in-first-out mode for this job

WorkerOptions

OptionTypeDefaultDescription
lifobooleanfalseFetch most recently added job first (applies to all fetches)

How It Works Internally

Priority

The store's fetchNextJob() method orders waiting jobs by priority (ascending), then by creation time. In SQL-based stores, this translates to:

sql
ORDER BY priority ASC, created_at ASC

A job with priority: 0 is fetched before priority: 10, which is fetched before priority: 100.

FIFO vs LIFO

  • FIFO (default): jobs are ordered by created_at ASC -- oldest first.
  • LIFO: jobs are ordered by created_at DESC -- newest first.

LIFO can be set at two levels:

  1. Per-job (JobOptions.lifo): marks the individual job for LIFO treatment.
  2. Per-worker (WorkerOptions.lifo): the worker always fetches in LIFO order.

Ordering Precedence

The complete fetch order is:

  1. State: only waiting jobs are eligible.
  2. Priority: lower number first.
  3. FIFO/LIFO: within the same priority, ordered by creation time.

Use Cases

Background vs Interactive

typescript
// User-triggered actions get high priority
await queue.add('resize-avatar', imageData, { priority: 1 });

// Batch imports run at low priority
await queue.add('import-csv', csvData, { priority: 50 });

Stack-Like Processing

Use LIFO when the most recent item is the most relevant:

typescript
// Latest sensor readings are more important than old ones
await queue.add('process-reading', sensorData, { lifo: true });

Default Job Options

Set a default priority for all jobs in a queue:

typescript
const queue = new Queue('background', {
  store,
  defaultJobOptions: { priority: 10 },
});

// All jobs in this queue default to priority 10
await queue.add('task', payload); // priority: 10
await queue.add('urgent', payload, { priority: 1 }); // override to 1

Caveats

  • Priority 0 is the default and highest. Use positive integers for lower priorities. Negative values are allowed and would be processed before 0.
  • LIFO is per-fetch, not per-queue. Setting lifo: true on a worker affects that worker's fetch order. Other workers processing the same queue can use different ordering.
  • Priority is static. Once a job is added, its priority cannot be changed. If you need dynamic priority, remove and re-add the job.
  • Interaction with delayed jobs. Delayed jobs are promoted to waiting when their delay expires. At that point, their priority takes effect among other waiting jobs.
  • No strict guarantee under concurrency. When multiple workers fetch simultaneously, the exact global order is best-effort. Each worker independently queries the store for the highest-priority waiting job.

See Also

  • Concurrency -- controls how many jobs run in parallel
  • Rate Limiting -- throttle throughput regardless of priority
  • Groups -- round-robin across groups with per-group ordering

Released under the MIT License.