Viktar Dubiniuk

shedder-shredder

  • #Go
  • #HTTP
  • #Docker Compose

Priority-based load shedding for http.Handler chains — middleware plus an interactive demo stack.

github.com/vicdeo/shedder-shredder →

Why this exists

When a service saturates, uniform rate limits treat a health check the same as an analytics ping. Load shedding is the middle ground: keep accepting work until you cannot, then drop the least important requests first and return 503 with Retry-After so clients back off.

shedder-shredder packages that logic as composable Go middleware, and ships a client + server demo to stress-test shedding behaviour under synthetic load — no Envoy, no mesh.

The middleware

Three priority tiers: high (never shed), medium, low. Each route wraps its handler with Middleware(priority).

Shedding decisions use:

Shed responses set X-Priority, return 503, and attach a random Retry-After between 3–10 seconds.

// Normal mode (simplified)
if inFlight >= mediumThreshold && priority < high { shed }
if avgLatency >= mediumLatencyThreshold && priority < high { shed }
if inFlight >= lowThreshold && priority == low { shed }
if avgLatency >= lowLatencyThreshold && priority == low { shed }

Thresholds are configured via environment variables (SH_LOW_THRESHOLD, SH_MEDIUM_THRESHOLD, SH_LOW_LATENCY_THRESHOLD, SH_MEDIUM_LATENCY_THRESHOLD).

Demo stack

Two binaries, one Compose file:

Binary Role
server (:8086) Slow simulated endpoints /high, /medium, /low (500–3000 ms). HTMX dashboard to switch shedding mode. WebSocket live stats.
client (:8085) Load generator UI — spawn N virtual users per priority (including random), hammer the server, stream results over WebSocket.
make docker-up    # distroless images, health probes via -probe

The client runs with a no-op shedder; only the server enforces shedding. Request IDs use UUID v7 (X-Request-ID).

Architecture

Package Role
internal/shedder Priority middleware, modes, atomic in-flight/latency counters
internal/webserver HandlePriorityFunc, request-ID middleware, server lifecycle
internal/user Virtual user pool and HTTP load generator
internal/websocket Broadcast stats and notifications to HTMX clients
templates/html Server and client control panels

Static binaries (CGO_ENABLED=0), Go 1.26.

What it is not

Not a production ingress controller. A reference implementation and playground for priority-tier shedding you can lift into your own http.Handler chain.

← All projects