fix(drivers): harden operator TimeoutMs handling + AbLegacy evict parity #454

Merged
dohertj2 merged 1 commits from fix/driver-timeout-hardening into master 2026-07-15 07:35:40 -04:00
Owner

Follow-ups from the fleet-wide read-timeout audit prompted by the S7 R2-01 read-leg fix (PR #453). Audit confirmed S7 was the only driver with the async-read-ignores-socket-timeout hang; these are the two adjacent non-hang findings.

  1. FOCAS TimeoutMs:0 footgun (risky): non-positive Timeout made SynchronizedFocasClient disable its per-call ceiling → frozen-peer wedge under misconfig. Clamp <=0 to the 2s default at the config boundary.
  2. TimeoutMs validation symmetry: same clamp in AbCip + AbLegacy factories (libplctag rejects <=0 on tag creation).
  3. AbLegacy evict parity: added EvictRuntime + wired into read/write non-zero-status and transport-exception paths to match AbCip's recreate-on-failure recovery.

Tests: FOCAS 269, AbCip 339, AbLegacy 212 — all green, no regressions.

Follow-ups from the fleet-wide read-timeout audit prompted by the S7 R2-01 read-leg fix (PR #453). Audit confirmed S7 was the only driver with the async-read-ignores-socket-timeout hang; these are the two adjacent non-hang findings. 1. **FOCAS `TimeoutMs:0` footgun** (risky): non-positive `Timeout` made `SynchronizedFocasClient` disable its per-call ceiling → frozen-peer wedge under misconfig. Clamp `<=0` to the 2s default at the config boundary. 2. **TimeoutMs validation symmetry**: same clamp in AbCip + AbLegacy factories (libplctag rejects `<=0` on tag creation). 3. **AbLegacy evict parity**: added `EvictRuntime` + wired into read/write non-zero-status and transport-exception paths to match AbCip's recreate-on-failure recovery. Tests: FOCAS 269, AbCip 339, AbLegacy 212 — all green, no regressions.
dohertj2 added 1 commit 2026-07-15 07:35:34 -04:00
fix(drivers): harden operator TimeoutMs handling + AbLegacy evict parity
v2-ci / build (pull_request) Successful in 4m5s
v2-ci / unit-tests (pull_request) Failing after 10m45s
a5a0f96d49
Follow-ups from the fleet-wide read-timeout audit that the S7 R2-01 read-leg
fix (PR #453) prompted. The audit confirmed S7 was the ONLY driver with the
async-read-ignores-socket-timeout hang; these are the two adjacent (non-hang)
findings it surfaced.

1. FOCAS TimeoutMs:0 footgun (the risky one): a non-positive Timeout made
   SynchronizedFocasClient DISABLE its per-call wall-clock ceiling, reverting to
   the caller's long-lived poll token — reintroducing exactly the frozen-peer
   wedge S7 just eliminated, under misconfig. Clamp non-positive TimeoutMs to the
   2s default at the config boundary so the deadline can never be authored away.

2. TimeoutMs validation symmetry: apply the same clamp in the AbCip + AbLegacy
   factories. libplctag's Tag.Timeout setter throws on <=0, faulting tag creation
   on every read/write; clamping keeps a misconfigured TimeoutMs:0 running on the
   default bound instead. (Shared PositiveTimeoutOrDefault helper per factory.)

3. AbLegacy reconnect parity with AbCip: AbLegacy evicted the cached libplctag
   runtime on neither the non-zero-status nor transport-exception read/write path
   (AbCip evicts on both), so a data-path fault recovered only via the probe loop
   / libplctag internals. Added EvictRuntime + wired it into both read and write
   failure paths so a fresh handle is created on the next call.

Tests: FOCAS 265->269 (clamp theory + positive), AbCip 336->339 (clamp theory +
positive), AbLegacy 209->212 (read-nonzero / read-exception / write-nonzero evict).
No production regressions; all three driver suites green.
dohertj2 merged commit a19c6b987c into master 2026-07-15 07:35:40 -04:00
Sign in to join this conversation.