fix(core): resolve Medium code-review finding (Core-006)
BuildAddressSpaceAsync now checks _disposed (throws ObjectDisposedException) and tears down the previous alarm forwarder + clears the sink registry before re-walking, so a Galaxy-redeploy rebuild does not leak the old forwarder and double-deliver alarm transitions. Three regression tests added: double-build does not double-fire, sink count is correct after rebuild, and post-dispose call throws. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -36,12 +36,25 @@ public class GenericDriverNodeManager(IDriver driver) : IDisposable
|
||||
/// Populates the address space by streaming nodes from the driver into the supplied builder,
|
||||
/// wraps the builder so alarm-condition sinks are captured, subscribes to the driver's
|
||||
/// alarm event stream, and routes each transition to the matching sink by <c>SourceNodeId</c>.
|
||||
/// Driver exceptions are isolated per decision #12 — the driver's subtree is marked Faulted,
|
||||
/// but other drivers remain available.
|
||||
/// If called a second time (e.g. Galaxy redeploy via <c>IRediscoverable.OnRediscoveryNeeded</c>)
|
||||
/// the previous alarm subscription is torn down and the sink registry is cleared before
|
||||
/// re-walking, preventing double delivery of alarm transitions.
|
||||
/// Exception isolation (marking the driver's subtree Faulted) is the caller's responsibility —
|
||||
/// exceptions from <see cref="ITagDiscovery.DiscoverAsync"/> propagate to the caller.
|
||||
/// </summary>
|
||||
public async Task BuildAddressSpaceAsync(IAddressSpaceBuilder builder, CancellationToken ct)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(builder);
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
// Tear down any previous alarm subscription before re-walking so a second call (e.g. on
|
||||
// Galaxy redeploy) does not leave the old forwarder subscribed and double-fire events.
|
||||
if (_alarmForwarder is not null && Driver is IAlarmSource existingSource)
|
||||
{
|
||||
existingSource.OnAlarmEvent -= _alarmForwarder;
|
||||
_alarmForwarder = null;
|
||||
}
|
||||
_alarmSinks.Clear();
|
||||
|
||||
if (Driver is not ITagDiscovery discovery)
|
||||
throw new NotSupportedException($"Driver '{Driver.DriverInstanceId}' does not implement ITagDiscovery.");
|
||||
|
||||
Reference in New Issue
Block a user