feat: add CLI debug snapshot command for one-shot instance state inspection

Adds `debug snapshot --id <int>` to query a running instance's current
attribute values and alarm states without the subscribe/stream overhead
of the debug view. Routes through ManagementActor → CommunicationService
→ site DeploymentManager → InstanceActor using the existing remote query
pattern.
This commit is contained in:
Joseph Doherty
2026-03-18 07:16:22 -04:00
parent 6ee820b0f0
commit 9c6e3c2e56
14 changed files with 144 additions and 4 deletions

View File

@@ -12,6 +12,7 @@ using ScadaLink.Commons.Entities.Notifications;
using ScadaLink.Commons.Entities.Security;
using ScadaLink.Commons.Entities.Sites;
using ScadaLink.Commons.Interfaces.Repositories;
using ScadaLink.Commons.Messages.DebugView;
using ScadaLink.Commons.Messages.Management;
using ScadaLink.Commons.Messages.RemoteQuery;
using ScadaLink.DeploymentManager;
@@ -109,7 +110,8 @@ public class ManagementActor : ReceiveActor
CreateInstanceCommand or MgmtDeployInstanceCommand or MgmtEnableInstanceCommand
or MgmtDisableInstanceCommand or MgmtDeleteInstanceCommand
or SetConnectionBindingsCommand
or MgmtDeployArtifactsCommand => "Deployment",
or MgmtDeployArtifactsCommand
or DebugSnapshotCommand => "Deployment",
// Read-only queries -- any authenticated user
_ => null
@@ -234,6 +236,7 @@ public class ManagementActor : ReceiveActor
// Remote Queries
QueryEventLogsCommand cmd => await HandleQueryEventLogs(sp, cmd),
QueryParkedMessagesCommand cmd => await HandleQueryParkedMessages(sp, cmd),
DebugSnapshotCommand cmd => await HandleDebugSnapshot(sp, cmd),
_ => throw new NotSupportedException($"Unknown command type: {command.GetType().Name}")
};
@@ -1105,4 +1108,19 @@ public class ManagementActor : ReceiveActor
DateTimeOffset.UtcNow);
return await commService.QueryParkedMessagesAsync(cmd.SiteIdentifier, request);
}
private static async Task<object?> HandleDebugSnapshot(IServiceProvider sp, DebugSnapshotCommand cmd)
{
var instanceRepo = sp.GetRequiredService<ITemplateEngineRepository>();
var instance = await instanceRepo.GetInstanceByIdAsync(cmd.InstanceId)
?? throw new InvalidOperationException($"Instance {cmd.InstanceId} not found.");
var siteRepo = sp.GetRequiredService<ISiteRepository>();
var site = await siteRepo.GetSiteByIdAsync(instance.SiteId)
?? throw new InvalidOperationException($"Site {instance.SiteId} not found.");
var commService = sp.GetRequiredService<CommunicationService>();
var request = new DebugSnapshotRequest(instance.UniqueName, Guid.NewGuid().ToString("N"));
return await commService.RequestDebugSnapshotAsync(site.SiteIdentifier, request);
}
}