perf(deploy): flatten-session caching, bulk DeploySiteAsync, paged management queries

This commit is contained in:
Joseph Doherty
2026-08-14 21:14:22 -04:00
parent ee193cd2bb
commit 48b3c40a7f
59 changed files with 3051 additions and 231 deletions
@@ -19,6 +19,7 @@ public static class DeployCommands
var command = new Command("deploy") { Description = "Deployment operations" };
command.Add(BuildInstance(urlOption, formatOption, usernameOption, passwordOption));
command.Add(BuildSite(urlOption, formatOption, usernameOption, passwordOption));
command.Add(BuildArtifacts(urlOption, formatOption, usernameOption, passwordOption));
command.Add(BuildStatus(urlOption, formatOption, usernameOption, passwordOption));
@@ -39,6 +40,43 @@ public static class DeployCommands
return cmd;
}
/// <summary>
/// Builds <c>deploy site</c> — bulk-deploy every instance at one site.
///
/// <para>
/// Sits under <c>deploy</c> alongside <c>deploy instance</c> and
/// <c>deploy artifacts</c>, naming the SCOPE of the deploy as the verb, which
/// is the convention the group already follows. Note it is deliberately NOT
/// fleet-wide when <c>--site-id</c> is omitted (the pattern <c>deploy
/// artifacts</c> uses): a bulk instance deploy is far more consequential than
/// an artifact push, so the target site is required rather than defaulted.
/// </para>
/// </summary>
private static Command BuildSite(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
{
var siteIdOption = new Option<int>("--site-id") { Description = "Target site ID", Required = true };
var cmd = new Command("site") { Description = "Deploy every deployable instance at a site" };
cmd.Add(siteIdOption);
cmd.SetAction(async (ParseResult result) =>
{
var siteId = result.GetValue(siteIdOption);
return await CommandHelpers.ExecuteCommandAsync(
result, urlOption, formatOption, usernameOption, passwordOption,
new MgmtDeploySiteCommand(siteId),
// A bulk deploy is N instance round-trips; the default 30 s client
// timeout would abandon the request while the server is still
// applying. Matches the server-side long-running Ask window.
timeout: BulkDeployTimeout);
});
return cmd;
}
/// <summary>
/// Client-side timeout for the bulk site deploy, matching the management
/// service's long-running command Ask window.
/// </summary>
internal static readonly TimeSpan BulkDeployTimeout = TimeSpan.FromMinutes(5);
private static Command BuildArtifacts(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
{
var siteIdOption = new Option<int?>("--site-id") { Description = "Target site ID (all sites if omitted)" };
+31
View File
@@ -952,6 +952,37 @@ scadabridge --url <url> deploy instance --id <int>
|--------|----------|-------------|
| `--id` | yes | Instance ID |
#### `deploy site`
Deploy **every deployable instance** at one site in a single batched operation.
Each instance keeps the full single-instance semantics — its own deployment ID and
revision hash, its own per-instance operation lock, its own optimistically-concurrent
status record, and the same query-before-redeploy idempotency check. The batch is
**not** all-or-nothing: an instance that cannot be deployed (wrong state, failed
validation, lock already held, site round-trip timed out) is reported as a failed row
and the rest proceed. Each failed instance is individually retryable with
`instance deploy --id`.
Site round-trips run with bounded concurrency
(`ScadaBridge:DeploymentManager:SiteDeploymentMaxParallelism`, default 4), each under
`SiteDeploymentTimeoutPerInstance` (default 120 s), so one wedged instance cannot stall
the batch. The client waits up to 5 minutes.
`--site-id` is **required** — unlike `deploy artifacts`, omitting it does not mean
fleet-wide.
```sh
scadabridge --url <url> deploy site --site-id <int>
```
| Option | Required | Description |
|--------|----------|-------------|
| `--site-id` | yes | Target site ID. A site-scoped (non-Administrator) Deployer must supply an in-scope site. |
Output is a per-instance result matrix (`instanceId`, `uniqueName`, `deploymentId`,
`success`, `errorMessage`) plus `successCount` / `failureCount`.
#### `deploy artifacts`
Deploy compiled artifacts to one or all sites (same as `site deploy-artifacts`).