@alasano/serverless-offline-localstack-sqs
v1.2.0
Published
Serverless Framework plugin for offline LocalStack SQS integration with local Lambda handlers
Downloads
635
Maintainers
Readme
Serverless Offline LocalStack SQS
A Serverless Framework plugin that enables local SQS integration with LocalStack for development and testing. This plugin automatically polls SQS queues and invokes your Lambda handlers locally, providing a seamless offline development experience.
Features
- ✅ Serverless Framework v3 & v4 Support - Compatible with both major versions
- ✅ LocalStack Integration - Works seamlessly with LocalStack SQS service
- ✅ Docker Auto-Detection - Automatically detects Docker environment and LocalStack endpoint
- ✅ Auto-Queue Creation - Creates queues from CloudFormation resources and function events
- ✅ Message Polling - Configurable polling intervals and concurrent processing
- ✅ Dead Letter Queue (DLQ) Support - Automatic retry and DLQ handling
- ✅ Batch Processing - Support for SQS batch message processing
- ✅ Hot Reloading - Automatic handler cache invalidation for development
- ✅ TypeScript Support - Written in TypeScript with full type definitions
- ✅ Comprehensive Logging - Debug-friendly logging with configurable levels
Installation
npm install --save-dev @alasano/serverless-offline-localstack-sqsQuick Start
- Add the plugin to your
serverless.yml:
plugins:
- serverless-offline
- serverless-offline-localstack-sqs
custom:
serverless-offline-localstack-sqs:
enabled: true
endpoint: http://localhost:4566 # LocalStack endpoint
autoCreate: true
debug: true- Start LocalStack:
docker run --rm -p 4566:4566 localstack/localstack- Start your serverless application:
serverless offline startThe plugin will automatically:
- Detect SQS events in your function definitions
- Create queues in LocalStack
- Start polling for messages
- Invoke your handlers when messages arrive
Configuration
Basic Configuration
custom:
serverless-offline-localstack-sqs:
enabled: true # Enable/disable the plugin
endpoint: http://localhost:4566 # LocalStack endpoint (auto-detected if omitted)
region: us-east-1 # AWS region
accessKeyId: test # LocalStack access key
secretAccessKey: test # LocalStack secret key
autoCreate: true # Auto-create queues from CloudFormation
pollInterval: 1000 # Polling interval in milliseconds
maxConcurrentPolls: 3 # Max concurrent polling operations
visibilityTimeout: 30 # Default visibility timeout
waitTimeSeconds: 20 # Long polling wait time
maxReceiveCount: 3 # Max retries before DLQ
deadLetterQueueSuffix: "-dlq" # DLQ naming suffix
debug: false # Enable debug logging
skipCacheInvalidation: false # Skip handler cache clearing
lambdaTimeout: 30000 # Handler timeout in millisecondsQueue Configuration
You can manually configure queues or let the plugin auto-detect them from your function events:
custom:
serverless-offline-localstack-sqs:
queues:
- queueName: my-queue
handler: handlers/processor.main
enabled: true
batchSize: 10
maxConcurrentPolls: 2
visibilityTimeout: 60
waitTimeSeconds: 20
timeout: 30 # Optional: Lambda timeout in seconds (overrides lambdaTimeout)
functionResponseTypes: # Optional: Enable partial batch responses
- ReportBatchItemFailures
dlq:
enabled: true
maxReceiveCount: 5
queueName: my-queue-dlq # Optional: custom DLQ nameFunction Events (Auto-Detection)
The plugin automatically detects SQS events from your function definitions:
functions:
processMessages:
handler: handlers/processor.main
events:
- sqs:
arn: arn:aws:sqs:us-east-1:000000000000:my-queue
batchSize: 10
functionResponseType: ReportBatchItemFailures # Enable partial batch responses
- sqs:
queueName: another-queue
batchSize: 1CloudFormation Resources
Queues defined in CloudFormation resources are automatically created:
resources:
Resources:
MyQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: my-queue
VisibilityTimeout: 30
RedrivePolicy:
deadLetterTargetArn: !GetAtt MyDLQ.Arn
maxReceiveCount: 3
MyDLQ:
Type: AWS::SQS::Queue
Properties:
QueueName: my-queue-dlqUsage Examples
Basic Handler
// handlers/processor.js
exports.main = async (event, context) => {
for (const record of event.Records) {
const messageBody = JSON.parse(record.body);
console.log("Processing message:", messageBody);
// Your processing logic here
await processMessage(messageBody);
}
return { statusCode: 200 };
};Error Handling with DLQ
// handlers/processor.js
exports.main = async (event, context) => {
for (const record of event.Records) {
try {
const messageBody = JSON.parse(record.body);
await processMessage(messageBody);
} catch (error) {
console.error("Processing failed:", error);
// Throw error to trigger retry/DLQ logic
throw error;
}
}
};Partial Batch Responses (ReportBatchItemFailures)
When functionResponseType: ReportBatchItemFailures is enabled, your handler can report which specific messages failed instead of failing the entire batch:
// handlers/processor.js
exports.main = async (event, context) => {
const batchItemFailures = [];
for (const record of event.Records) {
try {
const messageBody = JSON.parse(record.body);
await processMessage(messageBody);
// Message succeeded - no action needed
} catch (error) {
console.error(`Message ${record.messageId} failed:`, error);
// Mark this specific message as failed
batchItemFailures.push({ itemIdentifier: record.messageId });
}
}
// Return partial batch response
// Only failed messages will be retried; successful ones are deleted
return { batchItemFailures };
};Note: When batchItemFailures is empty or not returned, all messages are treated as successful.
Sending Test Messages
const { SQSClient, SendMessageCommand } = require("@aws-sdk/client-sqs");
const client = new SQSClient({
region: "us-east-1",
endpoint: "http://localhost:4566",
credentials: { accessKeyId: "test", secretAccessKey: "test" },
});
await client.send(
new SendMessageCommand({
QueueUrl: "http://localhost:4566/000000000000/my-queue",
MessageBody: JSON.stringify({ id: 1, message: "Hello World!" }),
}),
);Commands
The plugin provides custom Serverless commands:
# Start SQS polling only
serverless sqs-offline start
# Stop SQS polling
serverless sqs-offline stopDocker Integration
The plugin automatically detects your Docker environment:
- Docker Desktop: Uses
localhost:4566 - Running in Container: Uses
localstack:4566orhost.docker.internal:4566 - Custom Networks: Set
LOCALSTACK_HOSTenvironment variable
Docker Compose Example
version: "3.8"
services:
localstack:
image: localstack/localstack
ports:
- "4566:4566"
environment:
- SERVICES=sqs
- DEBUG=1
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"Troubleshooting
Plugin Not Starting
- Ensure LocalStack is running:
docker ps | grep localstack - Check plugin configuration in
serverless.yml - Enable debug logging:
debug: true
Messages Not Processing
- Verify queue names match between configuration and message sending
- Check handler paths are correct relative to service root
- Ensure LocalStack SQS is accessible on the configured endpoint
Handler Errors
- Check handler function exports match configuration
- Verify handler file extensions (
.js,.ts,.mjs) - Enable debug logging to see detailed error messages
Docker Connectivity
- Ensure port 4566 is not blocked by firewall
- For Docker Desktop on Windows/Mac, try
host.docker.internalinstead oflocalhost - Set
LOCALSTACK_HOSTenvironment variable if using custom networking
Development
Local Development
# Clone the repository
git clone https://github.com/alasano/serverless-offline-localstack-sqs.git
cd serverless-offline-localstack-sqs
# Install dependencies
npm install
# Build TypeScript
npm run build
# Run tests
npm test
# Run linter
npm run lintTesting with Examples
# Test with the simple test app
cd test-app
npm install
npm run dev
# Test with the examples
cd examples
npm install
npm run devGit Hooks
This project uses Husky for Git hooks to maintain code quality:
- Pre-commit hook: Runs
lint-stagedon staged files- Formats code with Prettier
- Automatically fixes ESLint issues where possible
- Prevents commits with linting errors
- Ensures consistent code style and formatting
# The pre-commit hook will run automatically, but you can also run manually:
npx lint-staged
# To bypass the hook (not recommended):
git commit --no-verify -m "message"CI/CD Pipeline
This project uses GitHub Actions for continuous integration and deployment:
CI Workflow (
ci.yml): Runs on every push and PR- Tests across Node.js 20 and 22
- Runs linting and unit tests
- Integration testing with LocalStack
- Code coverage reporting to Codecov
Release Workflow (
release.yml): Automated releases- Automatic version bumping based on commit messages
- GitHub release creation with changelog
- NPM publishing with proper permissions
- Manual release triggers with version selection
CodeQL Workflow (
codeql.yml): Security analysis- Weekly security scans
- Code quality and vulnerability detection
Release Process
The plugin supports both automatic and manual releases:
Automatic Releases:
- Push to
mainbranch triggers automatic patch releases - Commit messages determine version bump:
feat:orfeature:→ minor versionBREAKING:ormajor:→ major version- Default → patch version
Manual Releases:
- Go to Actions → Release workflow → Run workflow
- Select release type: patch, minor, major, or prerelease
Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes
- Add tests for new functionality
- Run the full test suite:
npm test - Run linting:
npm run lint - Commit with conventional commit messages
- Submit a pull request
License
MIT
