chore(management): log debug-stream push failures; fix event-log filter docs; refresh stale SourceNode note (arch-review S5/C7/C8)

Claude-Session: https://claude.ai/code/session_01MtdgwpEeCUn6cUA5f1LMPj
This commit is contained in:
Joseph Doherty
2026-07-10 06:07:19 -04:00
parent d6bad1738e
commit 4887461b64
4 changed files with 25 additions and 5 deletions
@@ -198,13 +198,15 @@ public class DebugStreamHub : Hub
// Use IHubContext for callbacks — the hub instance is transient (disposed after method returns),
// but IHubContext is a singleton that remains valid for the lifetime of the connection.
var hubClients = _hubContext.Clients;
// Capture the logger into a local: the callbacks outlive this (transient)
// hub instance, and ILogger is a singleton, so this is safe to hold.
var logger = _logger;
var session = await _debugStreamService.StartStreamAsync(
instanceId,
onEvent: evt =>
{
// Fire-and-forget — if the client disconnects, SendAsync will fail silently
_ = evt switch
var send = evt switch
{
AttributeValueChanged changed =>
hubClients.Client(connectionId).SendAsync("OnAttributeChanged", changed),
@@ -214,10 +216,20 @@ public class DebugStreamHub : Hub
hubClients.Client(connectionId).SendAsync("OnSnapshot", snapshot),
_ => Task.CompletedTask
};
// Fire-and-forget (deliberate — a slow/dead client must not block the
// stream), but log the push failure rather than swallowing it silently.
_ = send.ContinueWith(
t => logger.LogWarning(t.Exception?.GetBaseException(),
"Debug stream push to connection {ConnectionId} failed", connectionId),
CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
},
onTerminated: () =>
{
_ = hubClients.Client(connectionId).SendAsync("OnStreamTerminated", "Site disconnected");
_ = hubClients.Client(connectionId).SendAsync("OnStreamTerminated", "Site disconnected")
.ContinueWith(
t => logger.LogWarning(t.Exception?.GetBaseException(),
"Debug stream termination push to connection {ConnectionId} failed", connectionId),
CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
});
Context.Items[SessionIdKey] = session.SessionId;
@@ -3007,7 +3007,10 @@ public class ManagementActor : ReceiveActor
cmd.SiteIdentifier,
cmd.From, cmd.To,
cmd.EventType, cmd.Severity,
cmd.InstanceName, // InstanceId filter
// Instance unique-name filter — the site event log's instance_id column
// stores the instance UniqueName (InstanceActor.LogLifecycleEvent passes
// _instanceUniqueName; EventLogQueryService matches instance_id = $instanceId).
cmd.InstanceName,
cmd.Keyword,
null, // ContinuationToken
cmd.PageSize,