Files
ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Commons/Interfaces/Repositories/IDeploymentManagerRepository.cs
T

268 lines
17 KiB
C#

using ZB.MOM.WW.ScadaBridge.Commons.Entities.Deployment;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Instances;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Deployment;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
public interface IDeploymentManagerRepository
{
// DeploymentRecord
/// <summary>
/// Gets a deployment record by its ID.
/// </summary>
/// <param name="id">The deployment record ID.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>The deployment record, or null if not found.</returns>
Task<DeploymentRecord?> GetDeploymentRecordByIdAsync(int id, CancellationToken cancellationToken = default);
/// <summary>
/// Gets all deployment records.
/// </summary>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A read-only list of all deployment records.</returns>
Task<IReadOnlyList<DeploymentRecord>> GetAllDeploymentRecordsAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Gets all deployment records for a specific instance.
/// </summary>
/// <param name="instanceId">The instance ID.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A read-only list of deployment records for the instance.</returns>
Task<IReadOnlyList<DeploymentRecord>> GetDeploymentsByInstanceIdAsync(int instanceId, CancellationToken cancellationToken = default);
/// <summary>
/// Gets the current deployment status for an instance.
/// </summary>
/// <param name="instanceId">The instance ID.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>The current deployment record, or null if no deployment exists.</returns>
Task<DeploymentRecord?> GetCurrentDeploymentStatusAsync(int instanceId, CancellationToken cancellationToken = default);
/// <summary>
/// Gets a deployment record by deployment ID.
/// </summary>
/// <param name="deploymentId">The deployment ID.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>The deployment record, or null if not found.</returns>
Task<DeploymentRecord?> GetDeploymentByDeploymentIdAsync(string deploymentId, CancellationToken cancellationToken = default);
/// <summary>
/// Adds a new deployment record.
/// </summary>
/// <param name="record">The deployment record to add.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task AddDeploymentRecordAsync(DeploymentRecord record, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing deployment record.
/// </summary>
/// <param name="record">The deployment record to update.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task UpdateDeploymentRecordAsync(DeploymentRecord record, CancellationToken cancellationToken = default);
/// <summary>
/// Deletes a deployment record by ID, enforcing optimistic concurrency against the
/// supplied <paramref name="expectedRowVersion"/>. The caller MUST pass the
/// <c>RowVersion</c> it last observed on the record so EF emits
/// <c>DELETE ... WHERE Id = @id AND RowVersion = @prior</c>. A concurrent edit
/// surfaces as <see cref="Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException"/>
/// on <see cref="SaveChangesAsync(CancellationToken)"/>, matching the documented
/// "Optimistic concurrency is used on deployment status records" design rule.
/// </summary>
/// <param name="id">The deployment record ID to delete.</param>
/// <param name="expectedRowVersion">The RowVersion the caller observed; used as the optimistic-concurrency token.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task DeleteDeploymentRecordAsync(int id, byte[] expectedRowVersion, CancellationToken cancellationToken = default);
// SystemArtifactDeploymentRecord
/// <summary>
/// Gets a system artifact deployment record by ID.
/// </summary>
/// <param name="id">The system artifact deployment record ID.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>The system artifact deployment record, or null if not found.</returns>
Task<SystemArtifactDeploymentRecord?> GetSystemArtifactDeploymentByIdAsync(int id, CancellationToken cancellationToken = default);
/// <summary>
/// Gets all system artifact deployment records.
/// </summary>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A read-only list of all system artifact deployment records.</returns>
Task<IReadOnlyList<SystemArtifactDeploymentRecord>> GetAllSystemArtifactDeploymentsAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Adds a new system artifact deployment record.
/// </summary>
/// <param name="record">The system artifact deployment record to add.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task AddSystemArtifactDeploymentAsync(SystemArtifactDeploymentRecord record, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing system artifact deployment record.
/// </summary>
/// <param name="record">The system artifact deployment record to update.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task UpdateSystemArtifactDeploymentAsync(SystemArtifactDeploymentRecord record, CancellationToken cancellationToken = default);
/// <summary>
/// Deletes a system artifact deployment record by ID.
/// </summary>
/// <param name="id">The system artifact deployment record ID to delete.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task DeleteSystemArtifactDeploymentAsync(int id, CancellationToken cancellationToken = default);
// WP-8: DeployedConfigSnapshot
/// <summary>
/// Gets the deployed config snapshot for an instance.
/// </summary>
/// <param name="instanceId">The instance ID.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>The deployed config snapshot, or null if not found.</returns>
Task<DeployedConfigSnapshot?> GetDeployedSnapshotByInstanceIdAsync(int instanceId, CancellationToken cancellationToken = default);
/// <summary>
/// Adds a new deployed config snapshot.
/// </summary>
/// <param name="snapshot">The deployed config snapshot to add.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task AddDeployedSnapshotAsync(DeployedConfigSnapshot snapshot, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing deployed config snapshot.
/// </summary>
/// <param name="snapshot">The deployed config snapshot to update.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task UpdateDeployedSnapshotAsync(DeployedConfigSnapshot snapshot, CancellationToken cancellationToken = default);
/// <summary>
/// Deletes the deployed config snapshot for an instance.
/// </summary>
/// <param name="instanceId">The instance ID.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task DeleteDeployedSnapshotAsync(int instanceId, CancellationToken cancellationToken = default);
// Notify-and-fetch: PendingDeployment staging store
/// <summary>
/// Stages a flattened instance config for an in-flight deployment. Supersession:
/// any prior pending row for the same <c>InstanceId</c> is removed first, so at most
/// one pending row exists per instance (safe because the per-instance operation lock
/// serializes same-instance deploys). Does NOT call <see cref="SaveChangesAsync"/> —
/// the caller commits, mirroring the other Add/Delete repository methods.
/// </summary>
/// <param name="pending">The pending deployment to stage.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task AddPendingDeploymentAsync(PendingDeployment pending, CancellationToken cancellationToken = default);
/// <summary>
/// Gets a pending deployment by its deployment ID (the fetch key).
/// </summary>
/// <param name="deploymentId">The deployment ID.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>The pending deployment, or null if not found.</returns>
Task<PendingDeployment?> GetPendingDeploymentByIdAsync(string deploymentId, CancellationToken cancellationToken = default);
/// <summary>
/// Gets the pending deployment staged for a given instance (there is at most one per instance
/// by design — <see cref="AddPendingDeploymentAsync"/> supersedes and
/// <see cref="StagePendingIfAbsentAsync"/> inserts only if absent). Used by startup reconcile:
/// when <see cref="StagePendingIfAbsentAsync"/> reports a row already exists (a concurrent
/// reconcile from the other node, or an in-flight deploy), the handler reads that existing row
/// so a second concurrently-missing node can fetch the same pending config with its (multi-use,
/// TTL-bound) token instead of being omitted from the gap. Defensive against >1 row: returns
/// the most recently created one.
/// </summary>
/// <param name="instanceId">The instance whose pending deployment to read.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>The pending deployment for the instance, or null if none is staged.</returns>
Task<PendingDeployment?> GetPendingDeploymentByInstanceIdAsync(int instanceId, CancellationToken cancellationToken = default);
/// <summary>
/// Deletes a pending deployment by its deployment ID. No-op if not found. Does NOT
/// call <see cref="SaveChangesAsync"/> — the caller commits, mirroring the other
/// Add/Delete repository methods.
/// </summary>
/// <param name="deploymentId">The deployment ID to delete.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task DeletePendingDeploymentByIdAsync(string deploymentId, CancellationToken cancellationToken = default);
/// <summary>
/// Purges all pending deployments whose <c>ExpiresAtUtc</c> is at or before
/// <paramref name="nowUtc"/> (TTL maintenance). This is a self-contained maintenance
/// operation: it commits its own delete and returns the number of rows removed.
/// </summary>
/// <param name="nowUtc">The current UTC time; rows with <c>ExpiresAtUtc &lt;= nowUtc</c> are purged.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>The number of pending deployments purged.</returns>
Task<int> PurgeExpiredPendingDeploymentsAsync(DateTimeOffset nowUtc, CancellationToken cancellationToken = default);
// Startup reconciliation: expected-set query and insert-if-absent staging
/// <summary>
/// Returns the set of instances that central considers deployed for the given site — the join of
/// <c>DeployedConfigSnapshot</c> (by InstanceId) with <c>Instance</c> (where SiteId == siteId).
/// Instances without a snapshot are excluded. No <c>ConfigurationJson</c> is loaded; the full
/// config is fetched on demand via the HTTP endpoint using a freshly-minted token from
/// <see cref="StagePendingIfAbsentAsync"/>.
/// </summary>
/// <param name="siteId">The site primary key to filter on.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>All deployed instances for the site, as lightweight <see cref="ExpectedDeployment"/> projections.</returns>
Task<IReadOnlyList<ExpectedDeployment>> GetExpectedDeploymentsForSiteAsync(int siteId, CancellationToken cancellationToken = default);
/// <summary>
/// Inserts a <see cref="PendingDeployment"/> for the instance ONLY IF no pending row already
/// exists for that <c>InstanceId</c>. An existing pending row signals an in-flight deploy that
/// is already delivering to the node — do NOT supersede it (contrast with
/// <see cref="AddPendingDeploymentAsync"/>, which supersedes). Returns <c>true</c> if the row
/// was staged, <c>false</c> if an existing row was found and left untouched.
/// This method is self-contained: it commits its own save and returns a meaningful result,
/// matching the convention of <see cref="PurgeExpiredPendingDeploymentsAsync"/>.
/// </summary>
/// <param name="instanceId">The instance to stage the pending deployment for.</param>
/// <param name="deploymentId">The deployment ID (fetch key).</param>
/// <param name="revisionHash">Revision hash of the flattened configuration.</param>
/// <param name="configurationJson">JSON-serialized flattened configuration.</param>
/// <param name="token">Short-TTL fetch token the site node will present to the HTTP endpoint.</param>
/// <param name="createdAtUtc">UTC timestamp for this pending row.</param>
/// <param name="expiresAtUtc">UTC expiry after which the token is no longer valid.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns><c>true</c> if staged; <c>false</c> if a pending row already existed and was left unchanged.</returns>
Task<bool> StagePendingIfAbsentAsync(int instanceId, string deploymentId, string revisionHash,
string configurationJson, string token, DateTimeOffset createdAtUtc, DateTimeOffset expiresAtUtc,
CancellationToken cancellationToken = default);
// Instance lookups for deployment pipeline
/// <summary>
/// Gets an instance by ID.
/// </summary>
/// <param name="instanceId">The instance ID.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>The instance, or null if not found.</returns>
Task<Instance?> GetInstanceByIdAsync(int instanceId, CancellationToken cancellationToken = default);
/// <summary>
/// Gets an instance by unique name.
/// </summary>
/// <param name="uniqueName">The unique instance name.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>The instance, or null if not found.</returns>
Task<Instance?> GetInstanceByUniqueNameAsync(string uniqueName, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an instance.
/// </summary>
/// <param name="instance">The instance to update.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task UpdateInstanceAsync(Instance instance, CancellationToken cancellationToken = default);
/// <summary>
/// Removes an instance and everything that depends on it: deployment
/// records, deployed config snapshot, attribute/alarm overrides, and
/// connection bindings.
/// </summary>
/// <param name="instanceId">The instance ID to delete.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task DeleteInstanceAsync(int instanceId, CancellationToken cancellationToken = default);
/// <summary>
/// Saves all pending changes to the database.
/// </summary>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
/// <returns>A task representing the number of entities saved.</returns>
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
}