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) <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user