The occasional ECONNRESET

· ai · Source ↗

TLDR

  • Closing a TCP socket with unread data pending triggers a RST, causing intermittent ECONNRESET between localhost services like nginx and gunicorn.

Key Takeaways

  • Reproducer: server forks, dumps 600,000 bytes, closes socket; client sending data first (–spam) before reading causes ECONNRESET via TCP RST.
  • tcpdump and strace confirm RST originates from the server after close(), not from a crash or buffer overflow.
  • Root cause hypothesis: calling close() with unread incoming data on the socket causes the kernel to fire a RST instead of a clean FIN.
  • Real-world case: nginx splits HTTP requests across two writev() calls; gunicorn sometimes reads only the first 392-byte chunk (headers), ignores 22-byte body, then closes, triggering RST.
  • Workaround: force the Python/Flask app to read the full request body before responding; note this can open DoS risk for large POST bodies without nginx client_max_body_size limits.

Hacker News Comment Review

  • Commenters treat the close()-with-unread-data-causes-RST behavior as settled, well-documented TCP behavior for 30+ years, not a kernel quirk or bug.
  • The Apache httpd perf-tuning docs section on Lingering Close is flagged as essential reading for anyone building HTTP servers that need to avoid this pattern.

Original | Discuss on HN