lambda-throttle
v0.2.0
Published
Rate limiting for AWS Lambda functions with DynamoDB-backed persistence, per-key configurable limits, and SQS batch integration.
Maintainers
Readme
lambda-throttle
Rate limiting for AWS Lambda functions with DynamoDB-backed persistence, per-key configurable limits, and SQS batch integration.
Designed to work with @aws-lambda-powertools/batch and Middy middleware.
Installation
npm install lambda-throttle @aws-sdk/client-dynamodbQuick Start
SQS Batch Processing
Throttle message processing per key, returning rate limited messages back to the queue.
import { processPartialResponse, SqsFifoPartialProcessor } from '@aws-lambda-powertools/batch';
import { makeThrottled, ThrottleConfig } from 'lambda-throttle';
import { DynamoDBThrottlePersistenceLayer } from 'lambda-throttle/dynamodb';
import type { SQSEvent, SQSRecord } from 'aws-lambda';
const processor = new SqsFifoPartialProcessor();
const processRecord = makeThrottled(
async (record: SQSRecord) => {
const body = JSON.parse(record.body);
await callDownstreamService(body);
},
{
persistenceStore: new DynamoDBThrottlePersistenceLayer({
tableName: 'throttling-table',
}),
config: new ThrottleConfig({
throttleKeyJmesPath: 'body.selectedKey',
maxRequestsPerWindow: 50,
windowSeconds: 60,
}),
}
);
export const handler = async (event: SQSEvent) => {
return processPartialResponse(event, processRecord, processor);
};When a record exceeds the limit, ThrottleExceededError is thrown. The batch processor reports it as a batch item failure, and SQS makes the message available again after the visibility timeout.
Dynamic Per-Key Rate Limits
Set different limits based on a field in the message (e.g., tier):
import { ThrottleConfig } from 'lambda-throttle';
new ThrottleConfig({
throttleKeyJmesPath: 'body.tenantId',
maxRequestsPerWindow: {
jmesPath: 'body.tier',
mapping: { basic: 10, standard: 50, premium: 500 },
default: 20,
},
windowSeconds: 60,
})Middy Middleware
For API Gateway or direct invocations:
import middy from '@middy/core';
import { makeHandlerThrottled } from 'lambda-throttle/middleware';
import { DynamoDBThrottlePersistenceLayer } from 'lambda-throttle/dynamodb';
import { ThrottleConfig } from 'lambda-throttle';
export const handler = middy(async (event) => {
return { statusCode: 200, body: 'OK' };
}).use(
makeHandlerThrottled({
persistenceStore: new DynamoDBThrottlePersistenceLayer({ tableName: 'throttle-table' }),
config: new ThrottleConfig({
throttleKeyJmesPath: 'requestContext.identity.sourceIp',
maxRequestsPerWindow: 100,
windowSeconds: 60,
}),
})
);Configuration
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| throttleKeyJmesPath | string | undefined | JMESPath to extract the throttle key. Omit for global limit. |
| maxRequestsPerWindow | number \| object | — | Static limit or dynamic config with jmesPath, mapping, default. |
| windowSeconds | number | 60 | Fixed window duration in seconds. |
| hashAlgorithm | string | 'md5' | Hash algorithm for key generation ('md5', 'sha256', etc.). |
Dynamic Rate Limits
The maxRequestsPerWindow option accepts either a number or an object:
// Static
maxRequestsPerWindow: 100
// Extract a numeric limit directly from the payload
maxRequestsPerWindow: { jmesPath: 'body.rateLimit' }
// Map a string field to a limit
maxRequestsPerWindow: {
jmesPath: 'body.tier',
mapping: { basic: 10, standard: 50, premium: 500 },
default: 20,
}Per-Invocation Cache
When processing a batch of SQS records, once a key is throttled, all subsequent records with the same key in that batch are immediately rejected without hitting DynamoDB. This reduces costs and latency.
Disabling
Set the environment variable to disable throttling (e.g., for local development):
POWERTOOLS_THROTTLE_DISABLED=trueDevelopment
# Install
npm install
# Build
npm run build
# Unit tests
npm run test:unit
# Integration tests (requires LocalStack on localhost:4566)
npm run test:integration