mbproxy: add keepalive / connection monitoring

The DL205/DL260 ECOM emits no TCP keepalives, so an idle backend socket
can be silently dropped by a middlebox (switch, firewall, NAT) after
2-5 minutes. Enable OS SO_KEEPALIVE on backend and accepted upstream
sockets, and drive a periodic synthetic FC03 heartbeat on each idle
backend socket so a dead path is detected before a real client request
hits it. Controlled by Connection.Keepalive (ON by default).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-15 09:40:54 -04:00
parent 7466a46aa7
commit 0868613890
25 changed files with 1135 additions and 25 deletions
@@ -88,6 +88,9 @@ internal static class StatusHtmlRenderer
// an em-dash when no cache-eligible reads have occurred. Page-weight budget
// assertion stays under 50 KB for the 54-PLC fleet.
sb.Append("<th>Cache</th>");
// Keepalive column — heartbeats sent, with failure / idle-disconnect counts
// shown only when non-zero.
sb.Append("<th>Keepalive</th>");
sb.Append("</tr></thead><tbody>");
foreach (var plc in status.Plcs)
@@ -185,6 +188,24 @@ internal static class StatusHtmlRenderer
sb.Append(pct).Append("% (").Append(cacheHit).Append(')');
}
sb.Append("</td>");
// Keepalive cell — heartbeats sent; failures + idle-disconnects appended
// only when non-zero to keep the cell narrow.
long hbSent = plc.Backend.BackendHeartbeatsSent;
long hbFailed = plc.Backend.BackendHeartbeatsFailed;
long hbIdle = plc.Backend.BackendIdleDisconnects;
sb.Append("<td>");
if (hbSent == 0 && hbFailed == 0 && hbIdle == 0)
{
sb.Append("&mdash;");
}
else
{
sb.Append(hbSent);
if (hbFailed > 0 || hbIdle > 0)
sb.Append(" (fail ").Append(hbFailed)
.Append(", idle-disc ").Append(hbIdle).Append(')');
}
sb.Append("</td>");
sb.Append("</tr>");
}