Limitly
Examples

Advanced Configuration

Advanced usage patterns with tiered rate limiting, dynamic limits, and complex scenarios.

Advanced Configuration

Advanced patterns for complex rate limiting scenarios.

Tiered Rate Limiting

import { createClient } from 'limitly-sdk';

const client = createClient({ serviceId: 'tiered-api' });

const tierLimits = {
  free: { capacity: 100, refillRate: 10 },
  pro: { capacity: 1000, refillRate: 100 },
  enterprise: { capacity: 10000, refillRate: 1000 }
};

async function checkTieredLimit(user: User, endpoint?: string) {
  if (user.isAdmin) {
    return { allowed: true, limit: Infinity, remaining: Infinity };
  }
  
  const limits = tierLimits[user.plan];
  return await client.checkRateLimit({
    identifier: `${user.id}:${endpoint || 'default'}`,
    ...limits
  });
}

Dynamic Rate Limiting

import { createClient } from 'limitly-sdk';

const client = createClient({ serviceId: 'adaptive-api' });

// Simulate system load monitoring
async function getSystemLoad(): Promise<number> {
  // In real implementation, get from your monitoring system
  // Returns 0-100 representing CPU/memory usage
  return Math.random() * 100;
}

async function checkAdaptiveLimit(userId: string) {
  const systemLoad = await getSystemLoad();
  
  // Reduce limits when system is under heavy load
  const baseCapacity = 100;
  const baseRefillRate = 10;
  
  const capacity = systemLoad > 80 
    ? Math.floor(baseCapacity * 0.5)  // 50% capacity under high load
    : systemLoad > 50
    ? Math.floor(baseCapacity * 0.75) // 75% capacity under medium load
    : baseCapacity;                    // Full capacity under normal load
    
  const refillRate = systemLoad > 80
    ? Math.floor(baseRefillRate * 0.5)
    : systemLoad > 50
    ? Math.floor(baseRefillRate * 0.75)
    : baseRefillRate;
  
  return await client.checkRateLimit({
    identifier: userId,
    capacity,
    refillRate
  });
}

Time-Based Limiting

function getTimeBasedLimits() {
  const hour = new Date().getHours();
  return hour >= 9 && hour < 17
    ? { capacity: 50, refillRate: 5 }  // Peak hours
    : { capacity: 200, refillRate: 20 }; // Off-peak
}

await client.checkRateLimit({ identifier: userId, ...getTimeBasedLimits() });

Geographic Limiting

const regionLimits = {
  'US': { capacity: 100, refillRate: 10 },
  'ASIA': { capacity: 200, refillRate: 20 },
  'DEFAULT': { capacity: 50, refillRate: 5 }
};

const limits = regionLimits[country] || regionLimits['DEFAULT'];
await client.checkRateLimit({ identifier: `${userId}:${country}`, ...limits });

Multiple Windows

import { createClient } from 'limitly-sdk';

const client = createClient({ serviceId: 'multi-window' });

async function checkMultiWindowLimit(userId: string) {
  // Check multiple time windows
  const [minuteResult, hourResult, dayResult] = await Promise.all([
    // Per-minute limit
    client.checkRateLimit({
      identifier: `${userId}:minute`,
      capacity: 10,
      refillRate: 10,
      window: 60000  // 1 minute
    }),
    // Per-hour limit
    client.checkRateLimit({
      identifier: `${userId}:hour`,
      capacity: 1000,
      refillRate: 1000 / 3600,  // ~0.28 per second
      window: 3600000  // 1 hour
    }),
    // Per-day limit
    client.checkRateLimit({
      identifier: `${userId}:day`,
      capacity: 10000,
      refillRate: 10000 / 86400,  // ~0.12 per second
      window: 86400000  // 1 day
    })
  ]);
  
  // Request is allowed only if all windows allow it
  const allowed = minuteResult.allowed && hourResult.allowed && dayResult.allowed;
  
  return {
    allowed,
    windows: {
      minute: minuteResult,
      hour: hourResult,
      day: dayResult
    },
    // Return the most restrictive remaining count
    remaining: Math.min(
      minuteResult.remaining ?? Infinity,
      hourResult.remaining ?? Infinity,
      dayResult.remaining ?? Infinity
    )
  };
}

Burst Protection

Allow bursts but limit sustained traffic:

import { createClient } from 'limitly-sdk';

const client = createClient({ serviceId: 'burst-protection' });

async function checkBurstLimit(userId: string) {
  // Short window for burst detection
  const burstResult = await client.checkRateLimit({
    identifier: `${userId}:burst`,
    capacity: 20,      // Allow 20 requests
    refillRate: 20,   // Refill 20 per second
    window: 1000       // 1 second window
  });
  
  // Longer window for sustained rate
  const sustainedResult = await client.checkRateLimit({
    identifier: `${userId}:sustained`,
    capacity: 100,     // 100 requests
    refillRate: 10,    // Refill 10 per second
    window: 10000      // 10 second window
  });
  
  // Allow if either window allows (OR logic)
  // Or require both (AND logic) - current implementation
  const allowed = burstResult.allowed && sustainedResult.allowed;
  
  return {
    allowed,
    burst: burstResult,
    sustained: sustainedResult
  };
}

Rate Limit with Exponential Backoff

Implement exponential backoff for rate-limited users:

import { createClient } from 'limitly-sdk';

const client = createClient({ serviceId: 'backoff' });

interface RateLimitState {
  attempts: number;
  lastAttempt: number;
}

async function checkWithBackoff(userId: string): Promise<{
  allowed: boolean;
  backoffSeconds?: number;
  result: any;
}> {
  // Check standard rate limit
  const result = await client.checkRateLimit({
    identifier: userId,
    capacity: 100,
    refillRate: 10
  });
  
  if (result.allowed) {
    return { allowed: true, result };
  }
  
  // Calculate exponential backoff
  // Get previous attempt count from cache or database
  const state: RateLimitState = await getRateLimitState(userId);
  const attempts = state.attempts + 1;
  
  // Exponential backoff: 2^attempts seconds, max 60 seconds
  const backoffSeconds = Math.min(Math.pow(2, attempts), 60);
  
  // Store state
  await setRateLimitState(userId, {
    attempts,
    lastAttempt: Date.now()
  });
  
  return {
    allowed: false,
    backoffSeconds,
    result: {
      ...result,
      message: `Rate limited. Please retry after ${backoffSeconds} seconds.`,
      retryAfter: backoffSeconds
    }
  };
}

// Helper functions (implement with your cache/database)
async function getRateLimitState(userId: string): Promise<RateLimitState> {
  // Get from Redis, database, etc.
  return { attempts: 0, lastAttempt: 0 };
}

async function setRateLimitState(userId: string, state: RateLimitState): Promise<void> {
  // Store in Redis, database, etc.
}