fix(node): import a newly selected node inbound instead of sweeping it

Saving the node form writes the grown selection and marks the node dirty
in one transaction. On the next tick ReconcileNode runs before the
snapshot merge, and its delete sweep treats a selected tag with no
central row as "deleted on the master" — so an inbound the operator just
ticked in the picker (or every unselected one, when switching the node
to "all") is deleted from the node before the import that would have
created its row ever runs.

Nothing on disk separates "pending import" from "deleted while the node
was unreachable", but the pre-adoption guard already expresses the
former: while inbounds_adopted_at is zero the sweep waits for a clean
sync to adopt. A save that grows the managed set now zeroes it again,
and the same clean sync re-stamps it, so the offline-delete sweep is
only deferred by one successful sync, not disabled.

The trade: an inbound deleted on the master while the node was
unreachable is re-imported instead of swept if the operator grows the
node's selection during that same outage. That is visible and
recoverable, where the previous behaviour destroyed a live inbound.

Closes #6329
This commit is contained in:
Sanaei
2026-09-13 22:44:50 +02:00
parent 5ad9df69b9
commit 22346eef78
4 changed files with 96 additions and 3 deletions
+2 -2
View File
@@ -823,8 +823,8 @@ type Node struct {
ConfigDirty bool `json:"configDirty" gorm:"default:false"`
ConfigDirtyAt int64 `json:"configDirtyAt"`
// InboundsAdoptedAt records the first clean traffic sync that imported the
// node's pre-existing inbounds; reconcile must not sweep remote tags before it.
// InboundsAdoptedAt is the clean sync that imported the node's inbounds; a
// save that grows the selection zeroes it so reconcile waits before sweeping.
InboundsAdoptedAt int64 `json:"-" gorm:"column:inbounds_adopted_at;default:0"`
InboundCount int `json:"inboundCount" gorm:"-" example:"5"`