SPB Git

spb/ultra-sharp-agent-skills Public

Ultra-Sharp Agent Skills — a research-first skill-authoring system + 72 production-ready skills for AI agents.

Python 100%
3.8 KB · 125 lines markdown
Rendered Raw Blame History
1<!--2Author: Simon-Pierre Boucher3Contact: contact@spboucher.ai4-->56# Patterns — Rate Limiting78## Contents9- Token bucket in Redis (atomic)10- Response headers11- Cost-weighted limits12- Local fallback13- Penalty escalation14- Load shedding15- Gotchas1617## Token bucket in Redis (atomic)1819```lua20-- KEYS[1]=bucket key  ARGV: rate_per_s, burst, now_ms, cost21-- Returns {allowed(0/1), remaining, retry_after_s}22local rate, burst = tonumber(ARGV[1]), tonumber(ARGV[2])23local now, cost   = tonumber(ARGV[3]), tonumber(ARGV[4])24local b = redis.call('HMGET', KEYS[1], 'tokens', 'ts')25local tokens = tonumber(b[1]) or burst26local ts     = tonumber(b[2]) or now27tokens = math.min(burst, tokens + (now - ts) / 1000 * rate)28local allowed = tokens >= cost and 1 or 029if allowed == 1 then tokens = tokens - cost end30redis.call('HMSET', KEYS[1], 'tokens', tokens, 'ts', now)31redis.call('PEXPIRE', KEYS[1], math.ceil(burst / rate * 2000)) -- self-clean idle keys32local retry = allowed == 1 and 0 or math.ceil((cost - tokens) / rate)33return {allowed, math.floor(tokens), retry}34```3536```python37allowed, remaining, retry = redis.evalsha(38    SHA, 1, f"rl:{api_key}:{cls}", RATE, BURST, now_ms(), cost)39```4041One Lua call = read-modify-write with no race; never split GET/SET42across the network.4344## Response headers4546```python47def limit_headers(limit, remaining, reset_epoch):48    return {49        "X-RateLimit-Limit": str(limit),50        "X-RateLimit-Remaining": str(max(0, remaining)),51        "X-RateLimit-Reset": str(reset_epoch),52    }5354# On rejection add:55#   Retry-After: <seconds>   and body: {"error": "rate_limited", "retry_after": n}56```5758Send the X-RateLimit-* trio on 200s too — clients pace themselves only if59they can see the meter.6061## Cost-weighted limits6263```python64COSTS = {          # units per call; base=1. Weigh by measured backend cost.65    "search": 10,  # fans out to the search cluster66    "export": 25,  # long-running, memory heavy67    "read":   1,68    "health": 0,   # never throttle probes69}70cost = COSTS.get(endpoint_class, 1)71```7273## Local fallback7475```python76NODE_SHARE = RATE // max(node_count(), 1)  # conservative split when Redis is down7778def check(key, cost):79    try:80        return redis_bucket(key, cost)81    except RedisError:82        if key_route_is_sensitive(key):    # login/signup/reset/payment83            return REJECT                  # fail-closed84        return local_bucket(key, cost, rate=NODE_SHARE)  # fail-open, degraded85```8687## Penalty escalation8889```python90# Repeat offenders get exponentially longer cool-downs.91strikes = redis.incr(f"rl:strikes:{api_key}")92redis.expire(f"rl:strikes:{api_key}", 3600)93if strikes > 3:94    penalty = min(2 ** (strikes - 3) * 60, 3600)  # 1min → 1h cap95    redis.setex(f"rl:block:{api_key}", penalty, "1")96```9798## Load shedding99100```python101QUEUE_DEPTH_MAX = 100   # ≈ p99 concurrency × safety factor 2102def middleware(request):103    if executor.queue_depth() > QUEUE_DEPTH_MAX:104        return Response(503, headers={"Retry-After": "5"})105    ...106```107108Shed at the cheapest point in the stack (edge/middleware), before auth and109DB work — the point of shedding is to spend nothing on rejected requests.110111## Gotchas112113- **Fixed windows double-dose at boundaries**: 100/min allows 200 requests114  in the 2 s straddling the minute mark; token bucket doesn't.115- **Limiting after authentication** spends a DB call on every rejected116  request — put coarse anti-abuse limits before auth, fine per-user limits117  after.118- **`Retry-After: 0`** (rounding down) makes clients hammer instantly;119  always `ceil`.120- **One bucket for reads and writes** lets a read storm starve writes;121  split classes.122- **Missing `PEXPIRE` on buckets** leaks a key per client forever.123- **Health checks and load-balancer probes** must bypass limits or the LB124  will mark healthy nodes dead during an attack — exactly when you need them.125