b3b8313e9cf8b2691e95c45d7ef6b85d3d60a067
The 10-min stress test (1.46 M PDUs through the proxy) revealed that
status.json's bytes.upstreamIn / bytes.upstreamOut counters always read 0
because ProxyCounters.AddBytes was defined but never called from anywhere.
Same shape as the original review's W2.22 finding (counter wired in DTO +
HTML but no increment site), missed for the bytes counters specifically.
Wired five increment sites in PlcMultiplexer:
OnUpstreamFrameAsync (request side, parsed frame)
AddBytes(up: frame.Length, down: 0) — counted ONCE per parsed frame
regardless of subsequent routing (cache hit, coalesce, backend
round-trip, exception).
RunBackendReaderAsync fan-out (response side, after TrySendResponse=true)
AddBytes(up: 0, down: outFrame.Length) per delivered party. With
coalescing, one backend response fans out to N parties and produces
N × frame.Length bytes leaving the proxy upstream-side. Drops
(TrySendResponse=false) increment ResponseDropForFullUpstream
instead.
Cache hit path
AddBytes(up: 0, down: hitFrame.Length) for the BuildCacheHitFrame
response (no backend round-trip but still bytes leaving the proxy).
Saturation cleanup (W1.2 path, both branches)
AddBytes(up: 0, down: excFrame.Length) per delivered exception 0x04.
Non-coalescing-path saturation
AddBytes(up: 0, down: excFrame.Length) for the single exception 0x04.
Watchdog timeout exception delivery
AddBytes(up: 0, down: excFrame.Length) per delivered exception 0x0B.
Backend-side bytes (proxy ↔ PLC) are NOT counted by these counters — the
field name is `BytesUpstreamIn/Out` which is upstream-only by contract.
Tests: 387 pass / 0 fail.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Description
No description provided
Languages
C#
93.3%
TSQL
4.2%
PowerShell
1.5%
Shell
0.7%
Python
0.3%