@limitkit/redis
v1.2.0
Published
Redis store for LimitKit
Downloads
268
Maintainers
Readme
📦 @limitkit/redis
Redis-backed store and atomic rate limiting policies for LimitKit.
Designed for distributed systems, where multiple instances must share consistent rate limiting state.
Each request executes atomic Lua scripts, which avoids race conditions and ensures correctness even under high concurrency.
⚡ Installation
npm install @limitkit/core @limitkit/redis redisor, if your application uses ioredis:
npm install @limitkit/core @limitkit/redis ioredis⚡ Quick Start
import { RateLimiter } from "@limitkit/core";
import { RedisStore, fixedWindow } from "@limitkit/redis";
import { createClient } from "redis";
const client = createClient();
await client.connect();
const limiter = new RateLimiter({
store: new RedisStore(client),
rules: [
{
name: "global",
key: "global",
policy: fixedWindow({
window: 60,
limit: 100,
}),
},
],
});
await limiter.consume(ctx);🧠 How it works
Node.js applications send Lua scripts to Redis, which executes them atomically.
The execution result implies whether the request should be allowed or rejected.
app instances → script → Redis → decision🧩 What’s Included
🗄 Store
Create and pass a Redis client:
import { createClient } from "redis";
const client = createClient({
url: "redis://localhost:6379", // set this in a .env file
});
await client.connect();
new RedisStore(client);TypeScript may complain about the type mismatch. If needed, explicitly set the type of client to RedisClientType:
import { RedisClientType } from "redis";
const client: RedisClientType = createClient();You can also pass an ioredis client:
import Redis from "ioredis";
const client = new Redis("redis://localhost:6379");
new RedisStore(client);⚙️ Policies
@limitkit/redis includes optimized implementations of common rate limiting strategies.
You have to ensure all the policies use the algorithm functions below from @limitkit/redis
import { fixedWindow } from "@limitkit/redis";Fixed Window
fixedWindow({ window: 60, limit: 100 })Sliding Window
slidingWindow({ window: 60, limit: 100 })Sliding Window Counter
slidingWindowCounter({ window: 60, limit: 100 })Token Bucket
tokenBucket({ capacity: 100, refillRate: 5 })Leaky Bucket
leakyBucket({ capacity: 100, leakRate: 5 })Shaping Leaky Bucket
Shaping leaky bucket is a special algorithm that is typically used in worker queues to handle backpressure by delaying operations.
Simply create a store, a traffic shaper and call store.consume with the shaper. The result contains availableAt, which tells when to execute this job.
This reduces backpressure when producers enqueue too many tasks while consumers can't handle them fast enough.
import { createClient } from "redis";
import { RedisStore, shapingLeakyBucket } from "@limitkit/redis";
const redis = createClient();
await redis.connect();
const shaper = shapingLeakyBucket({
capacity: 100,
leakRate: 2 // requests per second
})
const redisStore = new RedisStore(redis);
// somewhere in code
const now = Date.now()
const result = await redisStore.consume(key, shaper, now, 1);
// schedule execution based on `availableAt`
setTimeout(() => handleJob(), result.availableAt - now);Alternatively, you can still create a limiter and call consume:
import { RateLimiter } from "@limitkit/core";
import { InMemoryStore, shapingLeakyBucket } from "@limitkit/memory";
const redis = createClient();
await redis.connect();
const limiter = new RateLimiter({
store: new RedisStore(redis),
rules: [
{
name: "queue",
key: (ctx) => ctx.queue.name, // handle backpressure for all the job queues
policy: shapingLeakyBucket({
capacity: 200,
leakRate: 4,
}),
},
],
});
// somewhere in code
const result = await limiter.consume(ctx);
setTimeout(() => handleJob(), result.rules[0].availableAt - now);GCRA
gcra({ burst: 5, interval: 1 })