mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-07 10:16:38 +08:00
fix: tolerate offline nodes when controlling forward services and editing tunnels
- controlForwardServices: skip offline nodes instead of failing entire operation, so forward pause/resume/delete works when some entry nodes are offline - onNodeOnline: always sync forward state on node reconnect (not just post-upgrade), so forwards that changed status while a node was offline get synced - add ListForwardIDsByNode repo method to sync all forwards (including paused) - tunnel edit UI: allow deselecting already-selected offline nodes in entry/chain/exit selectors, matching the backend's existing tolerance
This commit is contained in:
@@ -474,6 +474,9 @@ func (h *Handler) controlForwardServices(forward *forwardRecord, commandType str
|
|||||||
|
|
||||||
nodeHandled, lastNotFoundErr, err := h.controlForwardServicesOnNode(fp.NodeID, bases, commandType)
|
nodeHandled, lastNotFoundErr, err := h.controlForwardServicesOnNode(fp.NodeID, bases, commandType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if isNodeOfflineOrTimeoutError(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -389,9 +389,7 @@ func (h *Handler) consumeNodePendingUpgradeRedeploy(nodeID int64) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) onNodeOnline(nodeID int64) {
|
func (h *Handler) onNodeOnline(nodeID int64) {
|
||||||
if !h.consumeNodePendingUpgradeRedeploy(nodeID) {
|
h.consumeNodePendingUpgradeRedeploy(nodeID)
|
||||||
return
|
|
||||||
}
|
|
||||||
h.redeployNodeRuntimeAfterUpgrade(nodeID)
|
h.redeployNodeRuntimeAfterUpgrade(nodeID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,7 +399,7 @@ func (h *Handler) redeployNodeRuntimeAfterUpgrade(nodeID int64) {
|
|||||||
fmt.Printf("post-upgrade redeploy: list tunnels for node %d failed: %v\n", nodeID, err)
|
fmt.Printf("post-upgrade redeploy: list tunnels for node %d failed: %v\n", nodeID, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
forwardIDs, err := h.repo.ListActiveForwardIDsByNode(nodeID)
|
forwardIDs, err := h.repo.ListForwardIDsByNode(nodeID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("post-upgrade redeploy: list forwards for node %d failed: %v\n", nodeID, err)
|
fmt.Printf("post-upgrade redeploy: list forwards for node %d failed: %v\n", nodeID, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -99,6 +99,22 @@ func (r *Repository) ListActiveForwardIDsByNode(nodeID int64) ([]int64, error) {
|
|||||||
return ids, nil
|
return ids, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Repository) ListForwardIDsByNode(nodeID int64) ([]int64, error) {
|
||||||
|
if r == nil || r.db == nil {
|
||||||
|
return nil, errors.New("repository not initialized")
|
||||||
|
}
|
||||||
|
var ids []int64
|
||||||
|
err := r.db.Model(&model.ForwardPort{}).
|
||||||
|
Where("forward_port.node_id = ?", nodeID).
|
||||||
|
Select("DISTINCT forward_port.forward_id").
|
||||||
|
Order("forward_port.forward_id ASC").
|
||||||
|
Pluck("forward_port.forward_id", &ids).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ids, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Repository) ListForwardPorts(forwardID int64) ([]model.ForwardPortRecord, error) {
|
func (r *Repository) ListForwardPorts(forwardID int64) ([]model.ForwardPortRecord, error) {
|
||||||
if r == nil || r.db == nil {
|
if r == nil || r.db == nil {
|
||||||
return nil, errors.New("repository not initialized")
|
return nil, errors.New("repository not initialized")
|
||||||
|
|||||||
@@ -2184,16 +2184,27 @@ export default function TunnelPage() {
|
|||||||
<h3 className="text-lg font-semibold">入口配置</h3>
|
<h3 className="text-lg font-semibold">入口配置</h3>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Select
|
<Select
|
||||||
disabledKeys={[
|
disabledKeys={[
|
||||||
...nodes
|
...nodes
|
||||||
.filter((node) => node.status !== 1)
|
.filter(
|
||||||
.map((node) => node.id.toString()),
|
(node) =>
|
||||||
...(form.outNodeId || []).map((ct) =>
|
node.status !== 1 &&
|
||||||
ct.nodeId.toString(),
|
!(
|
||||||
),
|
isEdit &&
|
||||||
...getSelectedChainNodeIds().map((id) => id.toString()),
|
form.inNodeId.some(
|
||||||
]}
|
(ct) => ct.nodeId === node.id,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.map((node) => node.id.toString()),
|
||||||
|
...(form.outNodeId || []).map((ct) =>
|
||||||
|
ct.nodeId.toString(),
|
||||||
|
),
|
||||||
|
...getSelectedChainNodeIds().map((id) =>
|
||||||
|
id.toString(),
|
||||||
|
),
|
||||||
|
]}
|
||||||
errorMessage={errors.inNodeId}
|
errorMessage={errors.inNodeId}
|
||||||
isInvalid={!!errors.inNodeId}
|
isInvalid={!!errors.inNodeId}
|
||||||
label="入口节点"
|
label="入口节点"
|
||||||
@@ -2365,7 +2376,18 @@ export default function TunnelPage() {
|
|||||||
}}
|
}}
|
||||||
disabledKeys={[
|
disabledKeys={[
|
||||||
...nodes
|
...nodes
|
||||||
.filter((node) => node.status !== 1)
|
.filter(
|
||||||
|
(node) =>
|
||||||
|
node.status !== 1 &&
|
||||||
|
!(
|
||||||
|
isEdit &&
|
||||||
|
groupNodes.some(
|
||||||
|
(ct) =>
|
||||||
|
ct.nodeId === node.id &&
|
||||||
|
ct.nodeId !== -1,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
.map((node) => node.id.toString()),
|
.map((node) => node.id.toString()),
|
||||||
...form.inNodeId.map((ct) =>
|
...form.inNodeId.map((ct) =>
|
||||||
ct.nodeId.toString(),
|
ct.nodeId.toString(),
|
||||||
@@ -2626,7 +2648,18 @@ export default function TunnelPage() {
|
|||||||
}}
|
}}
|
||||||
disabledKeys={[
|
disabledKeys={[
|
||||||
...nodes
|
...nodes
|
||||||
.filter((node) => node.status !== 1)
|
.filter(
|
||||||
|
(node) =>
|
||||||
|
node.status !== 1 &&
|
||||||
|
!(
|
||||||
|
isEdit &&
|
||||||
|
(form.outNodeId || []).some(
|
||||||
|
(ct) =>
|
||||||
|
ct.nodeId === node.id &&
|
||||||
|
ct.nodeId !== -1,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
.map((node) => node.id.toString()),
|
.map((node) => node.id.toString()),
|
||||||
...form.inNodeId.map((ct) =>
|
...form.inNodeId.map((ct) =>
|
||||||
ct.nodeId.toString(),
|
ct.nodeId.toString(),
|
||||||
|
|||||||
Reference in New Issue
Block a user