Skip to main content

rate-limiting

Rate limiting implementation and strategies

Source facts

Repository
ffsshhttiikk/opencode-agents-skills
Last source activity
February 28, 2026 at 22:54
Detected SKILL.md language
English
Stars
3
Forks
2

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
rate-limiting
description
Rate limiting implementation and strategies
license
MIT
compatibility
opencode
metadata
{"audience":"developers","category":"security"}
## What I do - Implement rate limiting - Choose appropriate algorithms - Handle rate limit headers - Design tiered limits - Handle rate limit exceeded - Distribute rate limits - Monitor rate limit usage - Implement custom providers ## When to use me When implementing rate limiting or throttling. ## Rate Limiting Algorithms ```python from dataclasses import dataclass from datetime import datetime, timedelta from typing import Dict, Optional import asyncio # Fixed Window class FixedWindowRateLimiter: """ Simple fixed window rate limiting. Pros: Simple, memory efficient Cons: Can allow bursts at window boundaries """ def __init__(self, max_requests: int, window_seconds: int): self.max_requests = max_requests self.window_seconds = window_seconds self.windows: Dict[str, list] = {} def is_allowed(self, key: str) -> tuple[bool, dict]: now = datetime.utcnow() window_start = self._get_window_start(now) if key not in self.windows: self.windows[key] = [] # Remove old requests self.windows[key] = [ t for t in self.windows[key] if t >= window_start ] if len(self.windows[key]) >= self.max_requests: return False, { "limit": self.max_requests, "remaining": 0, "reset": int((window_start + timedelta(seconds=self.window_seconds)).timestamp()) } self.windows[key].append(now) return True, { "limit": self.max_requests, "remaining": self.max_requests - len(self.windows[key]), "reset": int((window_start + timedelta(seconds=self.window_seconds)).timestamp()) } def _get_window_start(self, now: datetime) -> datetime: seconds_past_window = now.timestamp() % self.window_seconds return now - timedelta(seconds=seconds_past_window) # Sliding Window class SlidingWindowRateLimiter: """ Sliding window rate limiting. Pros: More accurate than fixed window Cons: More complex, more memory """ def __init__(self, max_requests: int, window_seconds: int): self.max_requests = max_requests self.window_seconds = window_seconds self.requests: Dict[str, list] = {} def is_allowed(self, key: str) -> tuple[bool, dict]: now = datetime.utcnow() window_start = now - timedelta(seconds=self.window_seconds) if key not in self.requests: self.requests[key] = [] # Remove old requests self.requests[key] = [ t for t in self.requests[key] if t >= window_start ] if len(self.requests[key]) >= self.max_requests: return False, { "limit": self.max_requests, "remaining": 0, "reset": int((now + timedelta(seconds=self.window_seconds)).timestamp()) } self.requests[key].append(now) return True, { "limit": self.max_requests, "remaining": self.max_requests - len(self.requests[key]), "reset": int((now + timedelta(seconds=self.window_seconds)).timestamp()) } # Token Bucket class TokenBucketRateLimiter: """ Token bucket rate limiting. Pros: Allows bursts, smooth rate limiting Cons: More complex """ def __init__(self, max_tokens: int, refill_rate: float): self.max_tokens = max_tokens self.refill_rate = refill_rate # tokens per second self.tokens: Dict[str, float] = {} self.last_refill: Dict[str, datetime] = {} def _refill(self, key: str) -> float: now = datetime.utcnow() if key not in self.tokens: self.tokens[key] = self.max_tokens self.last_refill[key] = now return self.tokens[key] elapsed = (now - self.last_refill[key]).total_seconds() tokens_to_add = elapsed * self.refill_rate self.tokens[key] = min( self.max_tokens, self.tokens[key] + tokens_to_add ) self.last_refill[key] = now return self.tokens[key] def is_allowed(self, key: str, tokens: int = 1) -> tuple[bool, dict]: self._refill(key) if self.tokens[key] >= tokens: self.tokens[key] -= tokens return True, { "limit": self.max_tokens, "remaining": int(self.tokens[key]), } return False, { "limit": self.max_tokens": 0, , "remaining } ``` ## API Rate Limiting Middleware ```python from fastapi import Request, HTTPException from fastapi.responses import JSONResponse from starlette.middleware.base import BaseHTTPMiddleware class RateLimitMiddleware(BaseHTTPMiddleware): """Rate limiting middleware for FastAPI.""" def __init__( self, app, rate_limiter, exempt_paths: list = None ): super().__init__(app) self.rate_limiter = rate_limiter self.exempt_paths = exempt_paths or [] async def dispatch(self, request: Request, call_next): # Skip rate limiting for exempt paths if request.url.path in self.exempt_paths: return await call_next(request) # Get client identifier key = self._get_client_key(request) # Check rate limit allowed, headers = self.rate_limiter.is_allowed(key) if not allowed: return JSONResponse( status_code=429, headers={ **headers, "Retry-After": str(headers.get("reset", 60)), }, content={ "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Too many requests. Please retry later." } } ) response = await call_next(request) # Add rate limit headers for key, value in headers.items(): response.headers[key] = str(value) return response def _get_client_key(self, request: Request) -> str: """Get unique key for client.""" # Check for API key api_key = request.headers.get("X-API-Key") if api_key: return f"apikey:{api_key}" # Use user ID if authenticated if hasattr(request.state, "user_id"): return f"user:{request.state.user_id}" # Fall back to IP client_ip = request.client.host return f"ip:{client_ip}" ``` ## Distributed Rate Limiting with Redis ```python import redis from typing import Dict, Any class RedisRateLimiter: """Distributed rate limiter using Redis.""" def __init__( self, redis_url: str, max_requests: int = 100, window_seconds: int = 60 ): self.redis = redis.from_url(redis_url) self.max_requests = max_requests self.window_seconds = window_seconds def is_allowed(self, key: str) -> tuple[bool, dict]: now = datetime.utcnow() window_key = f"ratelimit:{key}:{int(now.timestamp() // self.window_seconds)}" pipe = self.redis.pipeline() # Increment counter pipe.incr(window_key) # Set expiry pipe.expire(window_key, self.window_seconds * 2) # Get current count results = pipe.execute() current_count = results[0] headers = { "X-RateLimit-Limit": str(self.max_requests), "X-RateLimit-Remaining": str(max(0, self.max_requests - current_count)), "X-RateLimit-Reset": str( int(now.timestamp()) + self.window_seconds ), } if current_count > self.max_requests: return False, headers return True, headers def sliding_window(self, key: str) -> tuple[bool, dict]: """More accurate sliding window using sorted sets.""" now = datetime.utcnow() window_start = now - timedelta(seconds=self.window_seconds) pipe = self.redis.pipeline() # Remove old entries pipe.zremrangebyscore( f"ratelimit:sliding:{key}", 0, window_start.timestamp() - 1 ) # Add current request pipe.zadd( f"ratelimit:sliding:{key}", {f"{now.timestamp()}:{uuid.uuid4()}": now.timestamp()} ) # Count requests in window pipe.zcard(f"ratelimit:sliding:{key}") # Set expiry pipe.expire( f"ratelimit:sliding:{key}", self.window_seconds * 2 ) results = pipe.execute() current_count = results[2] allowed = current_count <= self.max_requests return allowed, { "X-RateLimit-Limit": str(self.max_requests), "X-RateLimit-Remaining": str( max(0, self.max_requests - current_count) ), "X-RateLimit-Reset": str( int(now.timestamp()) + self.window_seconds ), } ``` ## Best Practices ``` Rate Limiting Best Practices: 1. Choose appropriate algorithm - Fixed window: simple, forgiving - Sliding window: more accurate - Token bucket: burst handling 2. Use tiered limits - Different limits for different users - Public vs authenticated 3. Return proper headers - X-RateLimit-Limit - X-RateLimit-Remaining - X-RateLimit-Reset - Retry-After 4. Handle exceeded gracefully - Clear error messages - Appropriate retry headers 5. Monitor and alert - Track rate limit hits - Alert on unusual patterns 6. Distribute across instances - Use shared storage (Redis) - Consistent hashing 7. Consider endpoint-specific - Different limits per endpoint - Expensive operations get lower limits 8. Allow some burst - Users expect occasional bursts - Token bucket handles this well 9. Test rate limiting - Verify limits are enforced - Test header values 10. Document limits - API documentation - Developer portal ```
View on GitHub