M4 R4.4: client-side multi-historian redundancy
Adds AVEVA.Historian.Client.Redundancy — HistorianRedundantClient orchestrates N single-historian members (IHistorianMember; default HistorianClientMember over HistorianClient) as one logical client. Pure client-side, no server-side redundancy protocol, no RE. - Reads fail over to the next member in priority order. Streaming reads only fail over BEFORE the first row is observed; a mid-stream failure propagates (failing over mid-stream would risk duplicated/skipped rows). - Writes fan out: WriteFanout AllMembers | PreferredOnly, with All | Any ack policy, returning a per-member HistorianRedundantWriteResult. - Per-member health: FailureThreshold demotes a failing member out of the preferred pool; a background watchdog (PeriodicTimer) + CheckHealthAsync re-probe and restore recovered members. GetStatus() snapshot + ActiveMember. - Composes with R4.1: back a member's writes with a HistorianStoreForwardWriter so a down member buffers and replays on recovery — the pragmatic client-side equivalent of native ReSyncTags. 14 unit tests (no server): failover order, mid-stream no-failover, all-fail aggregation, probe-any-up, fan-out ack policies, PreferredOnly, soft reject, health demotion + CheckHealthAsync restore, watchdog recovery. Full suite 307 green. Roadmap R4.4 marked shipped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B6mcaT2PjRFKcogzp9UkfC
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
namespace AVEVA.Historian.Client.Redundancy;
|
||||
|
||||
/// <summary>
|
||||
/// Thrown by a <see cref="HistorianRedundantClient"/> read when every member failed the operation.
|
||||
/// The per-member failures are aggregated in <see cref="Exception.InnerException"/> (an
|
||||
/// <see cref="AggregateException"/>).
|
||||
/// </summary>
|
||||
public sealed class HistorianAllMembersFailedException : Exception
|
||||
{
|
||||
public HistorianAllMembersFailedException(string operation, IReadOnlyList<Exception> failures)
|
||||
: base($"All historian members failed the '{operation}' operation.", new AggregateException(failures))
|
||||
{
|
||||
Operation = operation;
|
||||
}
|
||||
|
||||
/// <summary>The orchestrated operation that failed across all members.</summary>
|
||||
public string Operation { get; }
|
||||
}
|
||||
Reference in New Issue
Block a user