Adapt keepalive to the configured interval: for short intervals
(e.g. 10s) detection is faster, for long intervals (e.g. 10min)
it caps at 30s as a safety net. Add comments explaining what
problem keepalive solves and its detection time limitation.
Simplify the ghost connection fix by reusing the existing interval
duration as the write deadline. This removes the need for a separate
-write_deadline_ms flag while maintaining the same protection against
goroutine leaks from dead connections.
Connections closed by the kernel but not detected by endlessh-go cause
goroutines to run indefinitely, drifting open/closed Prometheus counters.
This happens because conn.Write() succeeds on dead connections when the
kernel buffers data. Kernel 6.12 (Debian 13) is more aggressive at
buffering, making ghosts permanent rather than self-healing.
Changes:
- Add SetWriteDeadline before conn.Write to detect dead connections
- Enable TCP keepalive (30s) on accepted connections for kernel-level
dead peer detection
- Add defer/recover in send goroutine for robustness
- Add -write_deadline_ms flag (default 30000, 0 to disable)
No new dependencies - uses only Go stdlib net package functions.