feat(historian-gateway): ContinuousHistorizationRecorder actor (outbox->WriteLiveValues, backoff)
Continuous-historization engine for non-Galaxy driver tags. Registers interest with the per-node DependencyMuxActor for the historized refs and taps the VirtualTagActor.DependencyValueChanged values the mux fans: coerce to numeric -> append to the durable IHistorizationOutbox (crash boundary) -> off-thread drain writes batches through IHistorianValueWriter and acks (FIFO-truncates) on success, backing off (exponential, capped) on failure. Non-numeric values are dropped + metered (SQL analog path is numeric-only). - New seam IHistorianValueWriter + HistorizationValue in Core.Abstractions so Runtime stays free of the gRPC driver. - GatewayHistorianValueWriter (driver) adapts IHistorianGatewayClient. WriteLiveValues: HistorizationValue -> HistorianLiveValue proto, WriteAck Success||Queued -> true; non-throwing (errors -> false for retry). - Drain runs via PipeTo(Self) so the mailbox never blocks on the gateway write; appends awaited on the actor thread to stay serialized. Adaptation vs plan: the mux fans DependencyValueChanged (TagId/Value/ TimestampUtc, no quality), not DriverInstanceActor.AttributeValuePublished, so values are recorded Good-quality (192) by the same convention the scripted-alarm host uses. Claude-Session: https://claude.ai/code/session_012SDSQ3AcaXqPcBtDESBRii
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions.Historian;
|
||||
|
||||
/// <summary>
|
||||
/// One numeric sample the continuous-historization recorder drains to the historian's SQL
|
||||
/// live-value write path. Carries the minimal payload that path can ingest: an optional UTC
|
||||
/// timestamp, the coerced numeric value, and an OPC-DA quality byte.
|
||||
/// </summary>
|
||||
/// <param name="TimestampUtc">
|
||||
/// UTC source timestamp of the sample, or <c>null</c> to defer to the historian's server-stamped
|
||||
/// current-time path (the SQL writer uses <c>SYSDATETIME()</c> when the timestamp is absent).
|
||||
/// </param>
|
||||
/// <param name="Value">The coerced numeric value (the SQL analog write path is numeric-only).</param>
|
||||
/// <param name="Quality">OPC-DA-derived quality code carried to the historian (192 = Good).</param>
|
||||
public readonly record struct HistorizationValue(DateTime? TimestampUtc, double Value, ushort Quality);
|
||||
|
||||
/// <summary>
|
||||
/// Seam over the historian's live-value write path used by the continuous-historization recorder.
|
||||
/// Lives in the abstraction layer so the Runtime recorder depends on it without taking a hard
|
||||
/// reference on the gRPC gateway driver; the gateway driver supplies the concrete adapter
|
||||
/// (<c>GatewayHistorianValueWriter</c>).
|
||||
/// </summary>
|
||||
public interface IHistorianValueWriter
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes a batch of live values for a single tag through the historian's SQL live-write path.
|
||||
/// Implementations are expected to be non-throwing: a transport/gateway error is surfaced as a
|
||||
/// <c>false</c> result so the recorder retains the entries and retries, rather than as an
|
||||
/// exception.
|
||||
/// </summary>
|
||||
/// <param name="tag">Fully-qualified historian tag the values are recorded against.</param>
|
||||
/// <param name="values">The numeric samples to write, in append order.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns><c>true</c> on a successful (or durably-queued) gateway ack; <c>false</c> on a retryable failure.</returns>
|
||||
Task<bool> WriteLiveValuesAsync(string tag, IReadOnlyList<HistorizationValue> values, CancellationToken ct);
|
||||
}
|
||||
Reference in New Issue
Block a user