fix(modbus): exception-safe batch wrapper; driver batch wiring consistency

This commit is contained in:
Joseph Doherty
2026-08-15 12:27:19 -04:00
parent f81cbabd2d
commit 5c61d0b133
7 changed files with 129 additions and 9 deletions
@@ -141,9 +141,19 @@ public sealed class ModbusDriver
{
if (!ShouldPublish(tagRef, snapshot)) return;
// Buffer what we publish so the cycle-end batch carries exactly the same items.
// The append stays OUTSIDE the catch below on purpose: as far as the batch contract
// is concerned the item WAS published — only the per-tag subscriber faulted — so it
// must still appear in this cycle's batch, keeping the two events content-identical.
_cycleBatchItems.GetOrAdd(handle, _ => new List<DataChangeItem>())
.Add(new DataChangeItem(tagRef, snapshot));
OnDataChange?.Invoke(this, new DataChangeEventArgs(handle, tagRef, snapshot));
// Defensive, mirroring PollGroupEngine.ReportError: the engine invokes this bridge
// UNGUARDED, so a throwing external subscriber would unwind PollOnceAsync mid-loop
// and the cycle would never reach onBatch. Because the buffer above persists across
// cycles (it is drained only by onBatch), those items would then silently MERGE into
// a later cycle's batch — cross-cycle contamination unique to this driver. Swallowing
// is what keeps the cycle running so onBatch drains the buffer on schedule.
try { OnDataChange?.Invoke(this, new DataChangeEventArgs(handle, tagRef, snapshot)); }
catch { /* a buggy subscriber must not corrupt the poll cycle */ }
},
onError: HandlePollError,
backoffCap: PollBackoffCap,