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
+10 -2
View File
@@ -150,6 +150,11 @@ internal sealed partial class ProxyWorker : BackgroundService
Func<ReadCoalescingOptions> coalescingAccessor =
() => _options.CurrentValue.Resilience.ReadCoalescing;
// Live accessor for KeepaliveOptions so a hot-reload of `Connection.Keepalive`
// propagates to the backend heartbeat loop and to upstream-socket keepalive.
Func<KeepaliveOptions> keepaliveAccessor =
() => _options.CurrentValue.Connection.Keepalive;
var supervisor = new PlcListenerSupervisor(
plc,
opts.Connection,
@@ -161,7 +166,8 @@ internal sealed partial class ProxyWorker : BackgroundService
recoveryPipeline,
_loggerFactory.CreateLogger<PlcListenerSupervisor>(),
backendPipeline,
coalescingAccessor);
coalescingAccessor,
keepaliveAccessor);
_supervisors[plc.Name] = supervisor;
}
@@ -175,7 +181,9 @@ internal sealed partial class ProxyWorker : BackgroundService
// (add/restart paths) honour hot-reloaded ReadCoalescing values.
Func<ReadCoalescingOptions> reconcilerCoalescingAccessor =
() => _options.CurrentValue.Resilience.ReadCoalescing;
_reconciler.Attach(_supervisors, opts, reconcilerCoalescingAccessor);
Func<KeepaliveOptions> reconcilerKeepaliveAccessor =
() => _options.CurrentValue.Connection.Keepalive;
_reconciler.Attach(_supervisors, opts, reconcilerCoalescingAccessor, reconcilerKeepaliveAccessor);
if (_supervisors.Count == 0)
{