namespace ZB.MOM.WW.ScadaBridge.DeploymentManager;
///
/// Configuration options for the central-side Deployment Manager.
///
public class DeploymentManagerOptions
{
///
/// Timeout for a lifecycle command round-trip (disable, enable, delete).
/// Applied as a linked-CTS deadline in DeploymentService so a hung or
/// unreachable site does not hold the per-instance operation lock indefinitely.
///
public TimeSpan LifecycleCommandTimeout { get; set; } = TimeSpan.FromSeconds(30);
/// Timeout per site for system-wide artifact deployment.
public TimeSpan ArtifactDeploymentTimeoutPerSite { get; set; } = TimeSpan.FromSeconds(120);
/// Timeout for acquiring an operation lock on an instance.
public TimeSpan OperationLockTimeout { get; set; } = TimeSpan.FromSeconds(5);
///
/// Maximum number of instance deployments whose SITE ROUND-TRIP runs
/// concurrently during a bulk DeploySiteAsync. The flatten/validate and
/// persistence phases stay serial regardless (they share one non-thread-safe
/// DbContext); only the network wait is fanned out.
///
///
/// Bounded rather than unbounded so a large site cannot open one in-flight
/// gRPC command per instance against a two-node site pair. Four mirrors the
/// conservative end of the site's own apply concurrency; raise it only with
/// evidence from the target-scale load test.
///
///
public int SiteDeploymentMaxParallelism { get; set; } = 4;
///
/// Per-instance deadline applied to the site round-trip inside a bulk
/// DeploySiteAsync. One unreachable or wedged instance is recorded as a
/// failed row and the rest of the batch continues — the bulk operation never
/// inherits a single instance's hang.
///
public TimeSpan SiteDeploymentTimeoutPerInstance { get; set; } = TimeSpan.FromSeconds(120);
///
/// Deadline applied to each query-before-redeploy reconciliation round-trip
/// inside a bulk DeploySiteAsync (the single-instance path keeps the
/// communication layer's own QueryTimeout).
///
///
/// Phase 1 is strictly serial, so an unreachable site otherwise costs
/// QueryTimeout (30 s) PER INSTANCE before a single deploy is sent — for
/// a 500-instance site roughly four hours, far past the CLI's 5-minute bulk
/// deploy timeout, which then cancels and re-arms the identical cost on the next
/// attempt. Deliberately short (seconds): a reconcile that does not answer
/// promptly falls through to a normal deploy anyway, which is exactly what its
/// own timeout produces. Works together with the once-per-batch reachability
/// circuit-breaker, which skips the remaining reconciles after the first
/// timeout.
///
///
public TimeSpan SiteDeploymentReconcileTimeout { get; set; } = TimeSpan.FromSeconds(5);
///
/// Retention window for TERMINAL deployment records (Success,
/// Failed). Deployments are insert-only — one row per attempt, forever —
/// so without a window the table grows without bound and every unfiltered
/// deployment query gets slower with the age of the system.
///
///
/// Deliberately generous (one year) because deployment history is
/// operator-facing forensics, and deliberately terminal-only: an
/// InProgress or Pending row is never purged regardless of age,
/// because it is exactly the row the query-before-redeploy reconciliation
/// path needs to find. Set to to disable purging.
///
///
public TimeSpan TerminalDeploymentRecordRetention { get; set; } = TimeSpan.FromDays(365);
///
/// How long the Central UI pending-updates snapshot stays fresh; one fleet
/// flatten per TTL while any Deployer/Administrator circuit is open.
///
///
/// The snapshot is a whole-fleet read (every site's artifact hash plus every
/// deployed instance's staleness), so it is held behind a single-flight TTL
/// cache: however many circuits poll, and however often, the fleet is evaluated
/// at most once per this window — and not at all when nobody is looking. Must be
/// positive; zero would make every poll a cache miss and re-flatten the fleet per
/// circuit, which is precisely the cost the cache exists to avoid.
///
///
public TimeSpan PendingUpdatesCacheTtl { get; set; } = TimeSpan.FromSeconds(60);
}