Skip to content

Queue transport

The queue transport routes background jobs to capability resolvers. No HTTP, no WebSocket — workers consume from a queue adapter and the execution engine processes each job.

See the package README for the full API.

When to use the queue transport

  • CPU-heavy tasks that should not block a request: report generation, image processing
  • Side effects that can be deferred: sending emails, syncing external systems
  • Capabilities that must not be exposed over HTTP
  • Fan-out patterns: one REST call enqueues many jobs

Setup

ts
import { createServer } from '@capixjs/core';
import { queueTransport, MemoryQueueAdapter, createQueueClient } from '@capixjs/transport-queue';

const adapter  = new MemoryQueueAdapter();
const jobQueue = createQueueClient(adapter, 'jobs');

createServer({
  context: buildContext,
  transports: [
    queueTransport({ queues: ['jobs'], adapter }),
  ],
  capabilities: {
    jobs: { processOrder, generateReport },
  },
}).start();

// Enqueue a job from anywhere in your application:
await jobQueue.enqueue('jobs.processOrder', { orderId: '123' });

Adapters

AdapterDescription
MemoryQueueAdapterIn-process queue. Jobs lost on restart. For dev and testing.
BullMQAdapterRedis-backed via BullMQ (pnpm add bullmq ioredis).
SqsQueueAdapterAmazon SQS — pass an @aws-sdk/client-sqs client and queue URLs. Failed jobs retry via the queue's visibility timeout and redrive policy.
Custom adaptersImplement QueueAdapter to use Faktory, NATS, or any queue system.
ts
import { SQS } from '@aws-sdk/client-sqs';
import { SqsQueueAdapter } from '@capixjs/transport-queue';

const adapter = new SqsQueueAdapter({
  client: new SQS({ region: 'eu-west-1' }),
  queueUrls: { jobs: process.env.JOBS_QUEUE_URL! },
});

Message format

Any system that can publish JSON to your queue can trigger Capix capabilities:

json
{
  "capability": "jobs.processOrder",
  "input": { "orderId": "123" }
}

Mixing REST and queue

Keep job-only capabilities off HTTP by using per-transport capabilities:

ts
createServer({
  context: buildContext,
  transports: [
    restTransport({ port: 3000, capabilities: { users, items } }),
    queueTransport({ queues: ['jobs'], adapter, capabilities: { jobs: { processOrder, generateReport } } }),
  ],
});

processOrder and generateReport are never exposed over HTTP.

Auth and guards

Jobs arrive with a minimal context — no real Authorization header. Guards that check ctx.user will see null unless you populate the context from the job input or a service account:

ts
const buildContext = defineContext(async (req) => {
  const serviceKey = getHeader(req, 'x-service-key');
  const user = serviceKey === process.env.QUEUE_SECRET
    ? SERVICE_ACCOUNT
    : await verifyJwt(getHeader(req, 'authorization'));
  return { requestId: crypto.randomUUID(), user, db };
});

The queue adapter can set x-service-key in the job metadata to signal that this is a trusted background job.

Released under the MIT License.