Fix connection lifecycle, pool bounds, and log rotation (review #007)

Critical:
- C1: Set server-side idle/keep-alive timeouts on both hyper builders
  (http2 keep_alive_interval=15s + keep_alive_timeout, http1
  header_read_timeout). Both builders now set TokioTimer (required to
  avoid runtime panic). Prevents FD exhaustion from abandoned TLS
  connections — the root cause of the 2026-07-24 outage.
- C2: Add Semaphore(max_connections) gating the accept loop. Provides
  backpressure via OS TCP backlog when all permits are taken.

Warnings:
- W1: Add SIGUSR1 log-reopen handler. New ReopenableFileWriter
  (Arc<ArcSwap<File>> via custom MakeWriter) atomically swaps the log
  file. Enables postrotate logrotate without copytruncate, which caused
  the 1.15GB sparse file that wedged fail2ban.
- W2: Set pool_max_idle_per_host(10) on both upstream clients, bounding
  idle upstream connections per host.
- W3: Add connection_idle_timeout_secs to StaticConfig (default 60).
- W4: Add max_connections to StaticConfig (default 1024).

Both new fields are validated (> 0) and included in static config drift
detection on reload. Docs (config.md, README, ADR-009) updated.
This commit is contained in:
glm-5.2 committed 2026-07-28 10:16:26 +00:00
1 parent e803817350
commit 0885486028
14 files changed
+407 -41

No files matched your search

@@ -10,6 +10,8 @@ The proxy needs to handle Unix signals for:
- **Graceful shutdown**: SIGTERM and SIGINT should stop accepting new
connections, drain in-flight requests, then exit.
- **Config reload**: SIGHUP should trigger a DynamicConfig reload from disk.
- **Log reopen**: SIGUSR1 should close and reopen the log file, enabling
`postrotate` logrotate configs without `copytruncate` (see review #007 W1).
Two approaches for signal handling:
- **`tokio::signal`**: Built into tokio. Handles SIGTERM and SIGINT via
@@ -22,6 +24,7 @@ Two approaches for signal handling:
Use `signal-hook` for all signal handling. Specifically:
- `signal-hook::flag` to set termination flags on SIGTERM/SIGINT
- `signal-hook` to register a SIGHUP handler that triggers config reload
- `signal-hook` to register a SIGUSR1 handler that reopens the log file
`tokio::signal::ctrl_c()` is registered as a secondary shutdown trigger; both
mechanisms converge on the same shutdown path. This is a belt-and-suspenders
@@ -34,6 +37,10 @@ The shutdown sequence:
for in-flight requests to complete, then exit with code 0.
2. On SIGHUP: re-read config file, validate, and swap DynamicConfig if valid.
Log the result.
3. On SIGUSR1: close the current log file handle and open a new one at the
same path. Enables standard `postrotate` logrotate configs (rename + signal)
without `copytruncate`, which creates sparse files when the FD offset is
high. See review #007 W1.
## Rationale