From 54d51a1d2056ef9e0e6e86df12dfd54af9379067 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Fri, 22 May 2026 09:26:42 -0400 Subject: [PATCH] fix(driver-ablegacy): resolve Medium code-review finding (Driver.AbLegacy-009) InitializeAsync catch block now mirrors ShutdownAsync teardown: cancels and disposes probe CancellationTokenSources, calls DisposeRuntimes, and clears _devices/_tagsByName before rethrowing. A caller that catches and abandons (rather than retrying via ReinitializeAsync) no longer leaves orphaned probe tasks or libplctag handles alive. Co-Authored-By: Claude Opus 4.7 (1M context) --- code-reviews/Driver.AbLegacy/findings.md | 4 ++-- .../AbLegacyDriver.cs | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/code-reviews/Driver.AbLegacy/findings.md b/code-reviews/Driver.AbLegacy/findings.md index 7e7b6ec..67c92c3 100644 --- a/code-reviews/Driver.AbLegacy/findings.md +++ b/code-reviews/Driver.AbLegacy/findings.md @@ -242,7 +242,7 @@ successful poll so a single failed read does not flap the surface. | Severity | Medium | | Category | Error handling & resilience | | Location | `AbLegacyDriver.cs:41-74` | -| Status | Open | +| Status | Resolved | **Description:** `InitializeAsync` starts probe loops with `Task.Run` inside the try block. If `InitializeAsync` fails - or is re-entered - after some probe loops are @@ -257,7 +257,7 @@ and `CancellationTokenSource`s alive holding libplctag handles. Separately, `ShutdownAsync` (cancel probe CTSs, dispose runtimes, clear dictionaries) before rethrowing, so a failed initialise leaves no live background work. -**Resolution:** _(open)_ +**Resolution:** Resolved 2026-05-22 — `InitializeAsync` catch block now cancels and disposes probe CTSs, calls `DisposeRuntimes`, and clears `_devices`/`_tagsByName` before rethrowing, leaving no orphaned background tasks or handles. ### Driver.AbLegacy-010 diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy/AbLegacyDriver.cs b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy/AbLegacyDriver.cs index 17d5759..44a451b 100644 --- a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy/AbLegacyDriver.cs +++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy/AbLegacyDriver.cs @@ -74,6 +74,20 @@ public sealed class AbLegacyDriver : IDriver, IReadable, IWritable, ITagDiscover catch (Exception ex) { _health = new DriverHealth(DriverState.Faulted, null, ex.Message); + // Tear down any probe loops and cached state that were created before the failure so + // that a caller who catches and abandons (rather than retrying via ReinitializeAsync) + // doesn't leave orphaned background tasks, CancellationTokenSources, and libplctag + // handles alive. Mirrors the body of ShutdownAsync without awaiting the poll engine + // (nothing has been subscribed yet at init time). + foreach (var state in _devices.Values) + { + try { state.ProbeCts?.Cancel(); } catch { } + state.ProbeCts?.Dispose(); + state.ProbeCts = null; + state.DisposeRuntimes(); + } + _devices.Clear(); + _tagsByName.Clear(); throw; } return Task.CompletedTask;