namespace ZB.MOM.WW.OtOpcUa.AdminUI.Hubs;
///
/// Raises a multicast delegate one subscriber at a time, so a subscriber that throws cannot stop
/// delivery to the subscribers after it. The in-process stores and broadcasters raise their events on
/// the bridge actor's thread; a plain handler?.Invoke(x) stops at the first throwing handler (for
/// example a Blazor circuit whose renderer is mid-teardown), so the remaining panels miss the update and
/// the exception escapes into the bridge actor, which restarts it.
///
internal static class SafeMulticast
{
/// Invokes every subscriber of with , isolating failures.
/// The event payload type.
/// The captured multicast delegate; null means no subscribers.
/// The payload passed to each subscriber.
/// Optional sink for a subscriber's exception; it must not throw.
/// The number of subscribers that threw.
public static int Invoke(Action? handler, T arg, Action? onError = null)
{
if (handler is null) return 0;
var failures = 0;
foreach (var subscriber in handler.GetInvocationList())
{
try
{
((Action)subscriber)(arg);
}
catch (Exception ex)
{
failures++;
try { onError?.Invoke(ex); }
catch { /* the error sink must never take delivery down with it */ }
}
}
return failures;
}
}