Golang stdlib-only
Note
Constraint: This project strictly uses the Go Standard Library. No external dependencies are permitted, ensuring a deep dive into core system engineering principles and the Go runtime.
FlowState is a dynamic L7 Reverse Proxy built in Go using only the stdlib.
- Build a stdlib-only Layer 7 reverse proxy to understand HTTP internals, connection reuse, and request lifecycle.
- Implement explicit routing, backend selection, and middleware composition without framework abstractions.
- Make timeouts, cancellation, health state, and observability first-class so behavior under failure is understandable.
- Favor clear control flow and measurable correctness over feature count.
- Not a production replacement for Envoy, NGINX, or Traefik.
- No dynamic control plane, distributed config, or service discovery at first.
- No HTTP/3, gRPC-native balancing, or WASM/plugin ecosystem.
- No external metrics/tracing libraries.
- Ingress path:
net/httpserver accepts request. - Router: matches host/path/method to a route entry.
- Middleware chain: request ID, logging, rate limiting, recovery, optional auth later.
- Load balancer: selects a healthy backend for the route.
- Proxy layer: rewrites request, injects forwarding headers, strips hop-by-hop headers, forwards via custom
http.RoundTripper. - Health subsystem: active probes + passive failure observation update backend state.
- Metrics/admin endpoints: expose counters, latency buckets, backend health.
Internal flow: server -> router -> middleware -> lb -> proxy transport -> response filters -> metrics
- If a backend times out, connection fails, or returns repeated 5xx responses, it may be marked unhealthy and removed from rotation.
- If all backends are unavailable, return
502or503consistently. - Client cancellation propagates to backend requests through
context.Context. - On shutdown, stop accepting new requests and allow in-flight requests to drain for a bounded time.
- No guarantee of zero request loss during process crash or forced termination.
Measure with testing.B, httptest, and simple load tools.
- Requests/sec through proxy with 1, 10, 100 concurrent clients.
- Latency: p50/p95/p99 under healthy backends.
- Tail latency under one slow backend.
- Cost of middleware stack.
- Effect of connection reuse vs disabled keep-alive.
- Load-balancer distribution fairness across backends.
- Unit tests for router matching, backend selection, health transitions, middleware behavior.
httptest.Serverintegration tests for end-to-end proxying.- Timeout/cancellation tests with slow handlers and canceled contexts.
- Race-detector runs for backend state, counters, and health updates.
- Fuzz tests for route parsing, config parsing, and header rewriting.
- Deterministic failure injection for connection errors and backend flapping.
- Static config loader
- Use:
encoding/jsonorencoding/gob/custom parser,os,flag - Learn: config modeling, validation, immutable runtime config
- Use:
- HTTP server bootstrap
- Use:
net/http,context,os/signal - Learn: server lifecycle, graceful shutdown, deadline propagation
- Use:
- Basic route matching
- Start simple: exact path + prefix match, host/method aware
- Use: slices/maps, longest-prefix match
- Learn: request dispatch, matching semantics
- Custom reverse proxy path
- Use:
net/http,net/url,io, custom handler instead of magic wrappers - Learn: request cloning, upstream URL rewriting, response copying
- Use:
- Custom transport
- Use:
http.Transport - Learn: keep-alives,
MaxIdleConns,MaxIdleConnsPerHost, dial timeout, TLS handshake timeout, response header timeout
- Use:
- Forwarding and hop-by-hop header handling
- Learn:
X-Forwarded-For,X-Forwarded-Proto, RFC hop-by-hop header stripping
- Learn:
- Weighted round robin
- Learn: stateful load balancing, atomic counters vs mutexes, fairness
- Request-scoped context and timeouts
- Use:
context.WithTimeout - Learn: cancellation propagation, bounded resource usage
- Use:
- Structured logging
- Use:
log/slog - Learn: request lifecycle logging, correlation IDs
- Use:
- Request ID middleware
- Use: headers + context values
- Learn: cross-cutting concerns, observability basics
- Recovery middleware
- Use:
defer,recover - Learn: panic boundaries in servers
- Use:
- Active health checks
- Use:
time.Ticker,net/httpornet.DialTimeout - Learn: health probe design, state transitions
- Use:
- Passive health checks
- Learn: consecutive failure counting, decay/reset, backend ejection
- Consistent unhealthy-backend policy
- Learn: fail-open vs fail-closed, cooldowns
- Graceful shutdown and backend draining
- Use:
http.Server.Shutdown - Learn: lifecycle management under load
- Use:
- Metrics endpoint
- Use:
expvaror custom text format vianet/http - Learn: counters, gauges, latency buckets
- Use:
- Trie router only if route count justifies it
- Learn: radix tree / trie, path parameter trade-offs
- Power of Two Choices
- Learn: queue-aware balancing, herd effect mitigation
- Token bucket rate limiter
- Use:
time,sync, monotonic refill math - Learn: admission control, backpressure
- Use:
- Connection pool tuning benchmarks
- Learn: transport tuning under concurrency
- Latency histograms / approximate percentiles
- Learn: buckets vs exact percentiles, tail latency measurement
- Zero-allocation hot-path cleanup where useful
- Learn: buffer reuse, avoiding needless header/value copies
- Circuit breaker
- Learn: closed/open/half-open FSM, rolling failure windows
- Hot config reload
- Use: atomic config swap, signal-driven reload
- Learn: read-copy-update style config management
- Per-route middleware policies
- Learn: policy composition and precedence
- Retry policy for idempotent requests only
- Learn: retry safety, duplicate side effects
- Outlier detection
- Learn: passive latency/error-based backend suppression