using System; using System.Threading; using System.Threading.Tasks; using Serilog; using ZB.MOM.WW.OtOpcUa.Driver.Historian.Wonderware.Ipc; namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.Wonderware.Backend { /// /// Production backed by AVEVA Historian's /// aahClientManaged alarm-event write API. The exact SDK entry point is /// pinned during the live-rig smoke in PR D.1 — until that gate, this backend /// reports for every /// event with a structured diagnostic so the lmxopcua-side /// SqliteStoreAndForwardSink retains the queued events rather than dropping /// or hard-failing them. /// /// /// /// Cluster failover reuses via /// the shared connection pool — there is /// no second connection pool for writes. Wonderware Historian's alarm-event /// write surface accepts the same HistorianAccess session a read /// opens, so reusing the picker is parity-preserving with v1's /// GalaxyHistorianWriter. /// /// /// Once D.1 confirms the SDK entry point, this class swaps the placeholder /// body for the real call sequence. The mapping from raw HRESULT / /// HistorianError codes onto /// is already shared via /// so the smoke-pinned change stays minimal. /// /// public sealed class SdkAlarmHistorianWriteBackend : IAlarmHistorianWriteBackend { private static readonly ILogger Log = Serilog.Log.ForContext(); private readonly HistorianConfiguration _config; public SdkAlarmHistorianWriteBackend(HistorianConfiguration config) { _config = config ?? throw new ArgumentNullException(nameof(config)); } public Task WriteBatchAsync( AlarmHistorianEventDto[] events, CancellationToken cancellationToken) { if (events is null || events.Length == 0) { return Task.FromResult(new AlarmHistorianWriteOutcome[0]); } // Placeholder: pin the SDK entry point in PR D.1 against a live AVEVA // Historian. Until then the call returns RetryPlease for every slot so // the lmxopcua-side sink keeps the events queued rather than dropping // them — same effect as the current NullAlarmHistorianSink fallback, // but visible through the structured diagnostic + per-event outcome. Log.Warning( "Alarm historian SDK write path not yet pinned — returning RetryPlease for {Count} event(s) from server {Server}. PR D.1 swaps this for the live aahClientManaged call.", events.Length, _config.ServerName); var outcomes = new AlarmHistorianWriteOutcome[events.Length]; for (var i = 0; i < outcomes.Length; i++) { outcomes[i] = AlarmHistorianWriteOutcome.RetryPlease; } return Task.FromResult(outcomes); } } }