Skip to content

RateLimiter.ts

Coordinates rate limits through shared persistent storage.

The RateLimiter service consumes tokens for string keys using fixed-window counters or token-bucket state. It can protect external APIs, enforce quotas, or throttle workers across fibers and processes that share the same store. This module includes helpers that fail when a limit is exceeded, return the delay needed before continuing, or wrap an effect so it waits automatically. It also defines the store service and in-memory or Redis-backed store layers.

Since v4.0.0



Provides a process-local in-memory RateLimiterStore.

Signature

declare const layerStoreMemory: Layer.Layer<RateLimiterStore, never, never>

Source

Since v4.0.0

Creates a Redis-backed RateLimiterStore using Lua scripts and the configured key prefix.

Signature

declare const makeStoreRedis: (
options?: { readonly prefix?: string | undefined } | undefined
) => Effect.Effect<
{
readonly fixedWindow: (options: {
readonly key: string
readonly tokens: number
readonly refillRate: Duration.Duration
readonly limit: number | undefined
}) => Effect.Effect<readonly [count: number, ttl: number], RateLimiterError>
readonly tokenBucket: (options: {
readonly key: string
readonly tokens: number
readonly limit: number
readonly refillRate: Duration.Duration
readonly allowOverflow: boolean
}) => Effect.Effect<number, RateLimiterError>
readonly adaptiveConsume: (
options: AdaptiveConsumeOptions
) => Effect.Effect<AdaptiveConsumeResult, RateLimiterError>
readonly adaptiveFeedback: (options: AdaptiveFeedbackOptions) => Effect.Effect<void, RateLimiterError>
},
never,
Redis.Redis
>

Source

Since v4.0.0

Accesses a function that sleeps when the rate limit is exceeded.

Example (Sleeping until rate limit permits)

import { Effect } from "effect"
import { RateLimiter } from "effect/unstable/persistence"
Effect.gen(function* () {
// Access the `sleep` function from the RateLimiter module
const sleep = yield* RateLimiter.makeSleep
// Use the `sleep` function with specific rate limiting parameters.
// This will only sleep if the rate limit has been exceeded.
yield* sleep({
key: "some-key",
limit: 10,
window: "5 seconds",
algorithm: "fixed-window"
})
})

Signature

declare const makeSleep: Effect.Effect<
(options: {
readonly algorithm?: "fixed-window" | "token-bucket" | undefined
readonly window: Duration.Input
readonly limit: number
readonly key: string
readonly tokens?: number | undefined
}) => Effect.Effect<ConsumeResult, RateLimiterError>,
never,
RateLimiter
>

Source

Since v4.0.0

Accesses a function that applies rate limiting to an effect.

Example (Applying rate limits to effects)

import { Effect } from "effect"
import { RateLimiter } from "effect/unstable/persistence"
Effect.gen(function* () {
// Access the `withLimiter` function from the RateLimiter module
const withLimiter = yield* RateLimiter.makeWithRateLimiter
// Apply a rate limiter to an effect
yield* Effect.log("Making a request with rate limiting").pipe(
withLimiter({
key: "some-key",
limit: 10,
onExceeded: "delay",
window: "5 seconds",
algorithm: "fixed-window"
})
)
})

Signature

declare const makeWithRateLimiter: Effect.Effect<
(options: {
readonly algorithm?: "fixed-window" | "token-bucket" | undefined
readonly onExceeded?: "delay" | "fail" | undefined
readonly window: Duration.Input
readonly limit: number
readonly key: string
readonly tokens?: number | undefined
}) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E | RateLimiterError, R>,
never,
RateLimiter
>

Source

Since v4.0.0

Creates a RateLimiter from the current RateLimiterStore.

Details

The limiter supports fixed-window and token-bucket algorithms and either fails or returns a delay when a limit is exceeded.

Signature

declare const make: Effect.Effect<RateLimiter, never, RateLimiterStore>

Source

Since v4.0.0

Error reason for a rate-limit check that exceeded the configured limit.

Details

Includes the affected key, limit, remaining token count, and retry delay.

Signature

declare class RateLimitExceeded

Source

Since v4.0.0

Error reason for failures in the backing RateLimiterStore.

Signature

declare class RateLimitStoreError

Source

Since v4.0.0

Error raised by rate limiter operations, wrapping a concrete failure reason.

Signature

declare class RateLimiterError {
constructor(props: { readonly reason: RateLimiterErrorReason })
}

Source

Since v4.0.0

Marks this value as a rate limiter error for runtime guards.

Signature

readonly [ErrorTypeId]: "~@effect/experimental/RateLimiter/RateLimiterError"

Source

Since v4.0.0

Schema for all reasons that can be carried by RateLimiterError.

Signature

declare const RateLimiterErrorReason: Schema.Union<[typeof RateLimitExceeded, typeof RateLimitStoreError]>

Source

Since v4.0.0

Union of reasons carried by RateLimiterError.

Signature

type RateLimiterErrorReason = RateLimitExceeded | RateLimitStoreError

Source

Since v4.0.0

Provides RateLimiter using the current RateLimiterStore.

Signature

declare const layer: Layer.Layer<RateLimiter, never, RateLimiterStore>

Source

Since v4.0.0

Provides a Redis-backed RateLimiterStore using makeStoreRedis.

Signature

declare const layerStoreRedis: (options?: {
readonly prefix?: string | undefined
}) => Layer.Layer<RateLimiterStore, never, Redis.Redis>

Source

Since v4.0.0

Provides a Redis-backed RateLimiterStore from wrapped configuration options.

Signature

declare const layerStoreRedisConfig: (
options: Config.Wrap<{ readonly prefix?: string | undefined }>
) => Layer.Layer<RateLimiterStore, Config.ConfigError, Redis.Redis>

Source

Since v4.0.0

Options for consuming tokens from the adaptive rate limiter store.

Signature

export interface AdaptiveConsumeOptions {
/**
* The rate-limit key.
*/
readonly key: string
/**
* The number of tokens to consume.
*/
readonly tokens: number
/**
* The fallback limit configured for the regular rate limiter.
*/
readonly fallbackLimit: number
/**
* The fallback window configured for the regular rate limiter.
*/
readonly fallbackWindow: Duration.Duration
}

Source

Since v4.0.0

Metadata returned after consuming tokens from the adaptive rate limiter store.

Signature

export interface AdaptiveConsumeResult {
/**
* The amount of delay to wait before making the request.
*/
readonly delay: Duration.Duration
/**
* The adaptive state epoch used to correlate later response feedback.
*/
readonly epoch: number
/**
* The adaptive phase observed by this consume operation.
*/
readonly phase: AdaptivePhase
}

Source

Since v4.0.0

Options for reporting response feedback to the adaptive rate limiter store.

Signature

export interface AdaptiveFeedbackOptions {
/**
* The rate-limit key.
*/
readonly key: string
/**
* The adaptive state epoch returned by `adaptiveConsume`.
*/
readonly epoch: number
/**
* The number of tokens consumed by the request.
*/
readonly tokens: number
/**
* The HTTP response status code.
*/
readonly status: number
/**
* The parsed `Retry-After` delay, when present.
*/
readonly retryAfter: Duration.Duration | undefined
}

Source

Since v4.0.0

Phase of adaptive rate limiting driven by server feedback.

Signature

type AdaptivePhase = "inactive" | "cooldown" | "learning" | "learned"

Source

Since v4.0.0

Metadata returned after consuming tokens from a rate limiter.

Signature

export interface ConsumeResult {
/**
* The amount of delay to wait before making the next request, when the rate
* limiter is using the "delay" `onExceeded` strategy. It will be
* Duration.zero if the request is allowed immediately.
*/
readonly delay: Duration.Duration
/**
* The maximum number of requests allowed in the current window.
*/
readonly limit: number
/**
* The number of remaining requests in the current window.
*/
readonly remaining: number
/**
* The time until the rate limit fully resets.
*/
readonly resetAfter: Duration.Duration
}

Source

Since v4.0.0

Service for consuming rate-limit tokens for a key using fixed-window or token-bucket algorithms.

Signature

export interface RateLimiter {
readonly [TypeId]: TypeId
readonly consume: (options: {
readonly algorithm?: "fixed-window" | "token-bucket" | undefined
readonly onExceeded?: "delay" | "fail" | undefined
readonly window: Duration.Input
readonly limit: number
readonly key: string
readonly tokens?: number | undefined
}) => Effect.Effect<ConsumeResult, RateLimiterError>
readonly adaptiveConsume: (options: AdaptiveConsumeOptions) => Effect.Effect<AdaptiveConsumeResult, RateLimiterError>
readonly adaptiveFeedback: (options: AdaptiveFeedbackOptions) => Effect.Effect<void, RateLimiterError>
}

Source

Since v4.0.0

Service tag for persistent token-consumption services.

When to use

Use to access or provide rate-limit checks backed by fixed-window counters or token-bucket state.

Signature

declare const RateLimiter: Context.Service<RateLimiter, RateLimiter>

Source

Since v4.0.0

Defines the low-level backing store for rate-limit state.

When to use

Use to provide the shared counter storage and adaptive feedback state used by persistent rate-limit checks.

Signature

declare class RateLimiterStore

Source

Since v4.0.0

Runtime type identifier for RateLimiterError.

Signature

declare const ErrorTypeId: "~@effect/experimental/RateLimiter/RateLimiterError"

Source

Since v4.0.0

Type-level identifier used to brand RateLimiterError values.

Signature

type ErrorTypeId = "~@effect/experimental/RateLimiter/RateLimiterError"

Source

Since v4.0.0

Runtime type identifier for RateLimiter values.

Signature

declare const TypeId: "~effect/persistence/RateLimiter"

Source

Since v4.0.0

Type-level identifier used to brand RateLimiter values.

Signature

type TypeId = "~effect/persistence/RateLimiter"

Source

Since v4.0.0