| name | langfuse-rate-limits |
| description | Implement Langfuse rate limiting, batching, and backoff patterns.
Use when handling rate limit errors, optimizing trace ingestion,
or managing high-volume LLM observability workloads.
Trigger with phrases like "langfuse rate limit", "langfuse throttling",
"langfuse 429", "langfuse batching", "langfuse high volume".
|
| allowed-tools | Read, Write, Edit |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
Langfuse Rate Limits
Overview
Handle Langfuse rate limits gracefully with batching and backoff strategies.
Prerequisites
- Langfuse SDK installed
- Understanding of async/await patterns
- High-volume trace workload
Rate Limit Tiers
| Tier | Events/min | Events/hour | Batch Size |
|---|
| Free | 1,000 | 10,000 | 15 |
| Pro | 10,000 | 100,000 | 50 |
| Enterprise | Custom | Custom | Custom |
Instructions
Step 1: Configure Optimal Batching
import { Langfuse } from "langfuse";
const langfuse = new Langfuse({
publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
secretKey: process.env.LANGFUSE_SECRET_KEY!,
flushAt: 50,
flushInterval: 5000,
requestTimeout: 30000,
});
Step 2: Implement Exponential Backoff
interface RetryConfig {
maxRetries: number;
baseDelayMs: number;
maxDelayMs: number;
jitterMs: number;
}
async function withBackoff<T>(
operation: () => Promise<T>,
config: RetryConfig = {
maxRetries: 5,
baseDelayMs: 1000,
maxDelayMs: 30000,
jitterMs: 500,
}
): Promise<T> {
for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
try {
return await operation();
} catch (error: any) {
if (attempt === config.maxRetries) throw error;
const status = error.status || error.response?.status;
if (status !== 429 && (status < 500 || status >= 600)) {
throw error;
}
retryAfter = error.?.?.();
: ;
(retryAfter) {
delay = (retryAfter) * ;
} {
exponentialDelay = config. * .(, attempt);
jitter = .() * config.;
delay = .(exponentialDelay + jitter, config.);
}
.(
+
);
( (r, delay));
}
}
();
}
Step 3: Rate Limit-Aware Wrapper
class RateLimitedLangfuse {
private langfuse: Langfuse;
private pendingEvents: number = 0;
private maxConcurrent: number = 100;
private queue: Array<() => void> = [];
constructor(config?: ConstructorParameters<typeof Langfuse>[0]) {
this.langfuse = new Langfuse({
...config,
flushAt: 50,
flushInterval: 5000,
});
}
private async waitForCapacity(): Promise<void> {
if (this.pendingEvents < this.maxConcurrent) {
this.pendingEvents++;
return;
}
return new Promise((resolve) => {
this.queue.( {
.++;
();
});
});
}
(): {
.--;
next = ..();
(next) ();
}
(
: < ..>[]
): << ..>> {
.();
{
..(params);
} {
.();
}
}
(): <> {
..();
}
(): <> {
..();
}
}
Step 4: Sampling for High Volume
interface SamplingConfig {
rate: number;
alwaysSample: (trace: TraceParams) => boolean;
}
class SampledLangfuse {
private langfuse: Langfuse;
private config: SamplingConfig;
constructor(
langfuseConfig: ConstructorParameters<typeof Langfuse>[0],
samplingConfig: SamplingConfig = { rate: 1.0, alwaysSample: () => false }
) {
this.langfuse = new Langfuse(langfuseConfig);
this.config = samplingConfig;
}
trace(params: Parameters<typeof this.langfuse.trace>[0]) {
if (this.config.alwaysSample(params)) {
return this.langfuse.(params);
}
(.() > ..) {
();
}
..({
...params,
: {
...params.,
: ,
: ..,
},
});
}
}
sampledLangfuse = (
{ : , : },
{
: ,
:
params.?.() || params. === ,
}
);
Output
- Optimized batching configuration
- Exponential backoff for rate limits
- Concurrent request limiting
- Sampling for ultra-high volume
Error Handling
| Header/Error | Description | Action |
|---|
| 429 Too Many Requests | Rate limited | Use exponential backoff |
| Retry-After | Seconds to wait | Honor this value exactly |
| X-RateLimit-Remaining | Requests left | Pre-emptive throttling |
| 503 Service Unavailable | Overloaded | Back off significantly |
Examples
Monitor Rate Limit Usage
class RateLimitMonitor {
private remaining: number = 1000;
private resetAt: Date = new Date();
updateFromResponse(headers: Headers) {
const remaining = headers.get("X-RateLimit-Remaining");
const reset = headers.get("X-RateLimit-Reset");
if (remaining) this.remaining = parseInt(remaining);
if (reset) this.resetAt = new Date(parseInt(reset) * 1000);
}
shouldThrottle(): boolean {
return this.remaining < 10 && new Date() < this.resetAt;
}
getWaitTime(): number {
return Math.max(0, this.resetAt.getTime() - Date.());
}
() {
{
: .,
: ..(),
: .(),
};
}
}
Batch Processing Pattern
async function processBatchWithRateLimits(items: any[]) {
const BATCH_SIZE = 50;
const DELAY_BETWEEN_BATCHES = 1000;
for (let i = 0; i < items.length; i += BATCH_SIZE) {
const batch = items.slice(i, i + BATCH_SIZE);
const traces = batch.map((item) =>
langfuse.trace({
name: "batch-item",
input: item,
})
);
await langfuse.flushAsync();
if (i + BATCH_SIZE < items.length) {
await new Promise((r) => setTimeout(r, DELAY_BETWEEN_BATCHES));
}
}
}
Queue-Based Rate Limiting
import PQueue from "p-queue";
const queue = new PQueue({
concurrency: 10,
interval: 1000,
intervalCap: 50,
});
async function queuedTrace(params: TraceParams) {
return queue.add(() => langfuse.trace(params));
}
Resources
Next Steps
For security configuration, see langfuse-security-basics.