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
| Target | Maps to | Notes |
|---|---|---|
aws | Lambda + SQS event source mapping | AWS manages polling, batching, retries. |
sprintsail-runtime | Deployment (1 replica) + in-process consume loop | The 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/maximumBatchingWindowlater (v1.1). - Runtime: 1 replica by default. Horizontal scaling lands in v1.1 alongside KEDA wiring.