fix(node): stop one rejected inbound from starving a node's traffic sync

A legacy socks inbound (predating the socks-to-mixed protocol rename) fails the node's request validation when pushed. ReconcileNode aborted on the first failed inbound and syncOne then skipped the traffic snapshot entirely and never cleared ConfigDirty, so the whole node re-failed every tick and the master stopped deducting traffic for every client on that node, exactly as reported in #5685.

Three-part fix: ReconcileNode now pushes every inbound and runs the delete sweep even past individual failures, returning the failures joined; syncOne logs a failed reconcile but continues with the traffic pull (dirty stays set, so reconcile retries and the merge stays in its conservative mode); and a migration renames legacy socks inbounds to mixed, which has an identical settings shape, removing the known trigger.

Closes #5685
This commit is contained in:
MHSanaei
2026-07-03 09:47:30 +02:00
parent 05cb70d8a8
commit d105b2741c
4 changed files with 119 additions and 9 deletions
+9 -6
View File
@@ -368,13 +368,16 @@ func (j *NodeTrafficSyncJob) syncOne(mgr *runtime.Manager, n *model.Node, doIpSy
reconcileErr := j.inboundService.ReconcileNode(reconcileCtx, rt, n)
reconcileCancel()
if reconcileErr != nil {
logger.Warningf("node traffic sync: reconcile for %s failed: %v", n.Name, reconcileErr)
return nil
// The dirty flag stays set so reconcile retries next tick, but traffic
// accounting must keep flowing: one rejected inbound used to starve the
// whole node's traffic/online sync forever (#5685).
logger.Warningf("node traffic sync: reconcile for %s failed, continuing with traffic pull: %v", n.Name, reconcileErr)
} else {
if clearErr := j.nodeService.ClearNodeDirty(n.Id, n.ConfigDirtyAt); clearErr != nil {
logger.Warningf("node traffic sync: clear dirty for %s failed: %v", n.Name, clearErr)
}
j.structural.set()
}
if clearErr := j.nodeService.ClearNodeDirty(n.Id, n.ConfigDirtyAt); clearErr != nil {
logger.Warningf("node traffic sync: clear dirty for %s failed: %v", n.Name, clearErr)
}
j.structural.set()
}
ctx, cancel := context.WithTimeout(context.Background(), nodeTrafficSyncRequestTimeout)