SQS Queue Handlers
defineSqsHandler creates Lambda handlers triggered by SQS queues. Import from @mantleframework/core.
The factory iterates over each record in the batch, calls your handler once per record, and returns a SQSBatchResponse with batchItemFailures for any records that threw. Failed records are retried without reprocessing successful ones.
Pattern
import { defineSqsHandler } from '@mantleframework/core'
interface SyncMessage {
userId: string
items: { id: string; value: number }[]
}
const sqs = defineSqsHandler<SyncMessage>({
queue: 'sync-queue',
batchSize: 10,
operationName: 'ProcessSyncQueue',
})
export const handler = sqs(async (record, metadata) => {
// record.body is typed as SyncMessage
await DataQueries.upsertBatch(record.body.items, record.body.userId)
})Options
| Option | Type | Default | Description |
|---|---|---|---|
queue | string | -- | Queue name — matches config.queues[].name for CLI infra wiring |
batchSize | number | -- | SQS batch size (CLI extraction marker, not runtime) |
parseBody | boolean | true | Parse record body as JSON |
operationName | string | function name | Name for metrics and tracing |
logging | LoggingConfig | -- | Fixture logging configuration |
timeout | number | -- | Lambda timeout in seconds |
memorySize | number | 128 | Lambda memory in MB |
reservedConcurrency | number | -- | Reserved concurrent executions |
ephemeralStorage | number | 512 | Ephemeral storage in MB |
deadLetterQueue | boolean | { targetArn? } | -- | true = auto-generate SQS DLQ |
retryAttempts | number | -- | Max retry attempts (0-2) |
Per-Record Callback
The inner handler is called once per SQS record and receives SqsRecordContext<TBody>:
interface SqsRecordContext<TBody = unknown> {
messageId: string // SQS message ID
body: TBody // Parsed JSON (if parseBody: true) or raw string
attributes: SQSRecordAttributes
messageAttributes: SQSMessageAttributes
receiptHandle: string // Receipt handle for manual deletion
rawRecord: SQSRecord // The raw SQS record
}The second argument is WrapperMetadata:
interface WrapperMetadata {
traceId: string
correlationId: string
}Retry vs Discard
By default any record that throws is added to batchItemFailures and SQS retries it. To permanently discard a record without retrying, return without throwing — or catch the error and handle it explicitly.
export const handler = sqs(async (record, metadata) => {
try {
await processRecord(record.body)
} catch (err) {
if (isUnrecoverable(err)) {
// Log and discard — do NOT rethrow
logger.error('Unrecoverable record, discarding', { messageId: record.messageId })
return
}
throw err // Rethrow to trigger SQS retry for this record
}
})Queue Config
The queue option must match a queue name declared in mantle.config.ts:
export default defineConfig({
queues: [
{ name: 'sync-queue' },
],
})The CLI uses this to wire the SQS trigger and IAM permissions automatically.
Raw Body (no JSON parsing)
Set parseBody: false to receive the raw string body:
const sqs = defineSqsHandler<string>({ queue: 'raw-queue', parseBody: false })
export const handler = sqs(async (record) => {
const raw = record.body // string
})File Location
SQS handlers live under src/lambdas/sqs/<HandlerName>/index.ts:
src/lambdas/sqs/
ProcessSyncQueue/
index.ts
HandleNotifications/
index.tsSee Also
- Handler Patterns — overview of all handler types
- S3 Triggers — S3 object event handlers