Skip to main content

Worker

A Worker consumes messages from a queue and runs a handler per message. Use it for asynchronous work — order processing, image transcoding, ETL.

Quick example

import { Project, Queue, Worker, Bucket } from '@sprintsail/sdk';

export const app = new Project('media');
export const inbox = new Queue(app, 'inbox', {});
export const archive = new Bucket(app, 'archive', { publicRead: false });

export const transcode = new Worker(app, 'transcode', {
handler: './src/handlers/transcode.ts',
memory: 1024,
triggers: [inbox], // queues that invoke this worker
bindings: { archive }, // resources the handler uses
});

Handler — same shape as Lambda's SQS event source mapping:

import { archive } from '../../infra.js';

export default async function handler(event: { Records: Array<{ messageId: string; body: string }> }) {
const { videoId, source } = JSON.parse(event.Records[0].body);
const result = await transcode(source); // your work
await archive.put(`videos/${videoId}.mp4`, result);
}

Config

interface WorkerConfig {
handler: string;
runtime?: 'nodejs22' | 'nodejs20' | 'python3.12';
memory?: number; // MB, default 256
env?: Record<string, string>;
triggers: Queue[]; // ≥1 required
bindings?: Record<string, Database | Bucket | Secret | Queue>;
}

triggers is required and must contain at least one Queue.

Target mapping

TargetMaps toNotes
awsLambda + SQS event source mappingAWS manages polling, batching, retries.
sprintsail-runtimeDeployment (1 replica) + in-process consume loopThe container runs runWorkerLoop from @sprintsail/runtime-sprintsail-runtime, connects to each trigger queue via amqplib, prefetch=1.

Dead-letter handling

When the handler throws, the worker republishes the failing message to a worker-owned <queue>.dlq (durable) with metadata headers — x-sail-error, x-sail-original-queue, x-sail-failed-at — and acks the original. This preserves poison messages for inspection without an infinite redelivery loop, and without requiring you to predeclare the main queue with x-dead-letter-* arguments (which would force producer/consumer declaration coordination).

On AWS, the standard SQS DLQ pattern applies — configure it on the Queue if you need it.

Triggers vs. Bindings

A trigger is a queue that invokes the worker. A binding is something the handler uses. The same Queue can be both (worker publishes back to its own input queue), but they're wired differently. See Bindings.

Scaling

  • AWS: SQS event source mapping handles concurrency. Add batchSize/maximumBatchingWindow later (v1.1).
  • Runtime: 1 replica by default. Horizontal scaling lands in v1.1 alongside KEDA wiring.