fix(historian): #674 review follow-ups — HistoryUpdate boot-window gate, node-level v1 refusal, plan-before-gate, UTC skew compare
- HistoryUpdate Primary gate now reads IHistoryUpdateRoleView (PrimaryGatePolicy.ShouldServeHistoryUpdate): the data-plane verdict but CLOSED until this node's first redundancy snapshot, so both pair nodes cannot accept in the pre-join boot window. Single nodes open on their own singleton's first snapshot; admin-only nodes register no view => no gate. DriverHostActor publishes it at every Primary-verdict publish point. - SqlServer v1: the updater throws NotSupportedException on every arm; the node manager maps it to a node-level BadHistoryOperationUnsupported (was per-item under a Good node for UpdateData/DeleteAtTime). HistoryWrite bit still advertised on v1 (not knowable at materialise time) — documented. - The update plan is evaluated before the Primary gate: an unservable request (Remove, IsDeleteModified, not historized, no updater) is BadHistoryOperationUnsupported off-Primary, not BadInvalidState. - Local-kind SourceTimestamp converted to UTC before the future-skew compare and sent as UTC. - Hosted-service wiring extracted to BuildHistoryUpdatePosture and tested (gate source, skew, clock). - Docs: Historian.md (boot window, ordering, node-level v1, HistoryWrite bit), CLAUDE.md. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -98,6 +98,11 @@ public static class ServiceCollectionExtensions
|
||||
// with no gate at all, and both nodes would write every sample twice with nothing to say so.
|
||||
services.TryAddSingleton<IHistorizationRoleView>(sp => sp.GetRequiredService<RedundancyRoleView>());
|
||||
|
||||
// Gitea #674 review: the OPC UA HistoryUpdate verdict — the data-plane verdict, but closed until this node's first
|
||||
// redundancy snapshot. Same instance; registered here (driver-role nodes only) so an admin-only node, which has no
|
||||
// redundancy manager, wires no HistoryUpdate gate at all.
|
||||
services.TryAddSingleton<IHistoryUpdateRoleView>(sp => sp.GetRequiredService<RedundancyRoleView>());
|
||||
|
||||
// The node→central ack transport under MeshTransport:Mode = Grpc (mesh gRPC command plane,
|
||||
// Task 1B.2). Registered unconditionally but resolved only by the Grpc arm of
|
||||
// WithOtOpcUaRuntimeActors — the mode is not knowable here (this runs before configuration is
|
||||
@@ -631,7 +636,9 @@ public static class ServiceCollectionExtensions
|
||||
// Review R6 MINOR-4: the passive half of a LocalDb pair has no PeerAddress, so it is told
|
||||
// its queue-sharing peer as its mesh partner instead — otherwise it never stands down.
|
||||
sharesAlarmQueueWithLocal: BuildAlarmQueuePeerPredicate(
|
||||
resolver.GetService<IConfiguration>(), roleInfo, replicationPeerHost)),
|
||||
resolver.GetService<IConfiguration>(), roleInfo, replicationPeerHost),
|
||||
// Gitea #674 review: the HistoryUpdate verdict (closed until the first redundancy snapshot).
|
||||
historyUpdateRoleView: resolver.GetService<IHistoryUpdateRoleView>()),
|
||||
DriverHostActorName);
|
||||
registry.Register<DriverHostActorKey>(driverHost);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user