Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/PepperDash.Essentials.Core/Routing/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -339,17 +339,21 @@ private static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOu

RoutingInputPort goodInputPort = null;

// Take a snapshot to avoid InvalidOperationException if TieLineCollection.Default is
// modified concurrently (e.g. NVX tie line registration during route requests).
var tieLines = TieLineCollection.Default.ToList();
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TieLineCollection.Default.ToList() still enumerates the underlying List<TieLine> and can throw InvalidOperationException if another thread modifies the collection during the snapshot. To fully address this, reads and writes of TieLineCollection.Default need synchronization (shared lock, or a thread-safe/copy-on-write collection), ideally via a safe snapshot method on TieLineCollection. Also, because this method is recursive, taking a new ToList() snapshot on every recursion can add significant allocation/CPU overhead; consider taking one snapshot in the public entry point and passing it down through the recursive calls.

Suggested change
var tieLines = TieLineCollection.Default.ToList();
List<TieLine> tieLines;
lock (TieLineCollection.Default)
{
tieLines = TieLineCollection.Default.ToList();
}

Copilot uses AI. Check for mistakes.

IEnumerable<TieLine> destinationTieLines;
TieLine directTie = null;

if (destinationPort == null)
{
destinationTieLines = TieLineCollection.Default.Where(t =>
destinationTieLines = tieLines.Where(t =>
t.DestinationPort.ParentDevice.Key == destination.Key && (t.Type.HasFlag(signalType) || signalType == eRoutingSignalType.AudioVideo));
}
else
{
destinationTieLines = TieLineCollection.Default.Where(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && (t.Type.HasFlag(signalType)));
destinationTieLines = tieLines.Where(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && (t.Type.HasFlag(signalType)));
}

// find the TieLine without a port
Expand Down
Loading