using ScadaLink.Commons.Types; namespace ScadaLink.Commons.Interfaces.Services; /// /// Audit Log #23 (M3 Bundle E — Tasks E4/E5): site-side hook the /// store-and-forward retry loop invokes after every cached-call attempt and /// at terminal-state transitions, so the audit pipeline can emit /// ApiCallCached/DbWriteCached per-attempt rows and the /// CachedResolve terminal row under the original /// . /// /// /// /// The interface deliberately uses /// rather than so the /// S&F project does not need to depend on the audit vocabulary — the /// bridge living in ScadaLink.AuditLog maps the outcome to the right /// audit kind + status when materialising the CachedCallTelemetry /// packet. /// /// /// Best-effort contract (alog.md §7): implementations MUST swallow /// internal failures rather than propagating to the S&F service — a /// thrown observer must not be misclassified as a transient delivery /// failure and must not corrupt the retry-count bookkeeping. /// /// public interface ICachedCallLifecycleObserver { /// /// Called by the store-and-forward retry loop after every cached-call /// delivery attempt. Receives the message's TrackedOperationId-bearing id, /// the per-category channel discriminator, retry-count + last-error /// context, and whether the outcome reached a terminal state. /// Task OnAttemptCompletedAsync(CachedCallAttemptContext context, CancellationToken ct = default); } /// /// Per-attempt context handed to . /// /// /// Tracking id parsed from the underlying StoreAndForwardMessage.Id. /// /// /// Trust-boundary channel string — "ApiOutbound" for ExternalSystem /// cached calls, "DbOutbound" for cached DB writes. /// /// Human-readable target (system name / DB connection). /// Site id that submitted the cached call. /// Per-attempt outcome. /// Number of retries performed so far (S&F bookkeeping). /// Most recent error message (null on success). /// Most recent HTTP status (null when not applicable). /// When the underlying S&F message was first enqueued. /// When this attempt completed. /// Duration of the attempt in milliseconds (null when not measured). /// Originating instance, when known. /// /// Audit Log #23 (ExecutionId Task 4): the originating script execution's /// per-run correlation id, threaded through the store-and-forward buffer from /// the cached-call enqueue path. The audit bridge stamps it onto the /// retry-loop ApiCallCached/DbWriteCached Attempted and /// CachedResolve rows so they correlate with the rest of the run. /// null for rows buffered before Task 4 (back-compat). /// /// /// Audit Log #23 (ExecutionId Task 4): the originating script identifier, /// threaded alongside so the retry-loop audit /// rows carry the same SourceScript provenance the script-side cached /// rows already do. null when not known. /// /// /// Audit Log #23 (ParentExecutionId Task 6): the ExecutionId of the /// inbound-API request that spawned the originating script execution, /// threaded through the store-and-forward buffer alongside /// . The audit bridge stamps it onto the /// retry-loop ApiCallCached/DbWriteCached Attempted and /// CachedResolve rows so they correlate back to the spawning run. /// null for a non-routed run and for rows buffered before Task 6 /// (back-compat). /// public sealed record CachedCallAttemptContext( TrackedOperationId TrackedOperationId, string Channel, string Target, string SourceSite, CachedCallAttemptOutcome Outcome, int RetryCount, string? LastError, int? HttpStatus, DateTime CreatedAtUtc, DateTime OccurredAtUtc, int? DurationMs, string? SourceInstanceId, Guid? ExecutionId = null, string? SourceScript = null, Guid? ParentExecutionId = null); /// /// Coarse outcome of one cached-call delivery attempt, observed from inside /// the store-and-forward retry loop. The audit bridge maps this to the /// ApiCallCached/DbWriteCached Attempted row and, when terminal, /// the corresponding CachedResolve row. /// public enum CachedCallAttemptOutcome { /// Attempt delivered successfully — terminal Delivered state. Delivered, /// Attempt failed transiently; another retry will follow. TransientFailure, /// Attempt returned permanent failure — terminal Parked state (S&F semantics). PermanentFailure, /// Retry budget exhausted — terminal Parked state. ParkedMaxRetries, }