From 6baee3e6c314cb0302ac8006d48ceda5cae1aa5a Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 28 Apr 2026 12:40:57 +0000 Subject: [PATCH] types: add Unhealthy and SessionEpoch fields to Node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Runtime-only fields (gorm:"-") that the upcoming refactor folds into NodeStore's snapshot: - Unhealthy: replaces routes.PrimaryRoutes.unhealthy set; written by HA prober. - SessionEpoch: replaces the external connectGen sync.Map; bumped inside Connect's NodeStore update closure so stale Disconnect rejection becomes atomic with the mutation. No behaviour change yet — fields are unread. Updates #3203 --- hscontrol/types/node.go | 10 ++++++++++ hscontrol/types/types_clone.go | 2 ++ hscontrol/types/types_view.go | 13 ++++++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/hscontrol/types/node.go b/hscontrol/types/node.go index fe7638c9..2a4e0e7d 100644 --- a/hscontrol/types/node.go +++ b/hscontrol/types/node.go @@ -154,6 +154,16 @@ type Node struct { DeletedAt *time.Time IsOnline *bool `gorm:"-"` + + // Unhealthy excludes the node from primary route election while + // online. Written by the HA prober. Runtime-only. + Unhealthy bool `gorm:"-"` + + // SessionEpoch identifies a poll session. Connect bumps it; a + // Disconnect carrying a stale value is dropped, so a deferred + // disconnect from a previous session cannot overwrite a newer + // Connect. Runtime-only. + SessionEpoch uint64 `gorm:"-"` } type Nodes []*Node diff --git a/hscontrol/types/types_clone.go b/hscontrol/types/types_clone.go index be22b350..163c22c8 100644 --- a/hscontrol/types/types_clone.go +++ b/hscontrol/types/types_clone.go @@ -106,6 +106,8 @@ var _NodeCloneNeedsRegeneration = Node(struct { UpdatedAt time.Time DeletedAt *time.Time IsOnline *bool + Unhealthy bool + SessionEpoch uint64 }{}) // Clone makes a deep copy of PreAuthKey. diff --git a/hscontrol/types/types_view.go b/hscontrol/types/types_view.go index bdbd0f77..6684ecd6 100644 --- a/hscontrol/types/types_view.go +++ b/hscontrol/types/types_view.go @@ -258,7 +258,16 @@ func (v NodeView) DeletedAt() views.ValuePointer[time.Time] { func (v NodeView) IsOnline() views.ValuePointer[bool] { return views.ValuePointerOf(v.ж.IsOnline) } -func (v NodeView) String() string { return v.ж.String() } +// Unhealthy excludes the node from primary route election while +// online. Written by the HA prober. Runtime-only. +func (v NodeView) Unhealthy() bool { return v.ж.Unhealthy } + +// SessionEpoch identifies a poll session. Connect bumps it; a +// Disconnect carrying a stale value is dropped, so a deferred +// disconnect from a previous session cannot overwrite a newer +// Connect. Runtime-only. +func (v NodeView) SessionEpoch() uint64 { return v.ж.SessionEpoch } +func (v NodeView) String() string { return v.ж.String() } // A compilation failure here means this code must be regenerated, with the command at the top of this file. var _NodeViewNeedsRegeneration = Node(struct { @@ -285,6 +294,8 @@ var _NodeViewNeedsRegeneration = Node(struct { UpdatedAt time.Time DeletedAt *time.Time IsOnline *bool + Unhealthy bool + SessionEpoch uint64 }{}) // View returns a read-only view of PreAuthKey.