diff --git a/go-backend/internal/http/handler/upgrade.go b/go-backend/internal/http/handler/upgrade.go index 19b9dca..99e0cbb 100644 --- a/go-backend/internal/http/handler/upgrade.go +++ b/go-backend/internal/http/handler/upgrade.go @@ -6,6 +6,7 @@ import ( "io" "net/http" "strings" + "sync" "time" "go-backend/internal/http/response" @@ -16,6 +17,8 @@ const ( githubProxy = "https://gcode.hostcentral.cc" githubAPIBase = "https://api.github.com" githubHTMLBase = "https://github.com" + upgradeTimeout = 5 * time.Minute + batchWorkers = 5 ) func (h *Handler) nodeUpgrade(w http.ResponseWriter, r *http.Request) { @@ -59,7 +62,7 @@ func (h *Handler) nodeUpgrade(w http.ResponseWriter, r *http.Request) { result, err := h.wsServer.SendCommand(req.ID, "UpgradeAgent", map[string]interface{}{ "downloadUrl": downloadURL, "checksumUrl": checksumURL, - }, 120*time.Second) + }, upgradeTimeout) if err != nil { response.WriteJSON(w, response.Err(-2, fmt.Sprintf("升级失败: %v", err))) return @@ -173,18 +176,29 @@ func (h *Handler) nodeBatchUpgrade(w http.ResponseWriter, r *http.Request) { Message string `json:"message"` } - results := make([]upgradeResult, 0, len(req.IDs)) - for _, id := range req.IDs { - result, err := h.wsServer.SendCommand(id, "UpgradeAgent", map[string]interface{}{ - "downloadUrl": downloadURL, - "checksumUrl": checksumURL, - }, 120*time.Second) - if err != nil { - results = append(results, upgradeResult{ID: id, Success: false, Message: err.Error()}) - } else { - results = append(results, upgradeResult{ID: id, Success: true, Message: result.Message}) - } + results := make([]upgradeResult, len(req.IDs)) + sem := make(chan struct{}, batchWorkers) + var wg sync.WaitGroup + + for i, id := range req.IDs { + wg.Add(1) + go func(index int, nodeID int64) { + defer wg.Done() + sem <- struct{}{} + defer func() { <-sem }() + + result, err := h.wsServer.SendCommand(nodeID, "UpgradeAgent", map[string]interface{}{ + "downloadUrl": downloadURL, + "checksumUrl": checksumURL, + }, upgradeTimeout) + if err != nil { + results[index] = upgradeResult{ID: nodeID, Success: false, Message: err.Error()} + return + } + results[index] = upgradeResult{ID: nodeID, Success: true, Message: result.Message} + }(i, id) } + wg.Wait() response.WriteJSON(w, response.OK(map[string]interface{}{ "version": version, diff --git a/go-gost/x/socket/websocket_reporter.go b/go-gost/x/socket/websocket_reporter.go index 22bb362..743f510 100644 --- a/go-gost/x/socket/websocket_reporter.go +++ b/go-gost/x/socket/websocket_reporter.go @@ -485,9 +485,8 @@ func (w *WebSocketReporter) handleReceivedMessage(messageType int, message []byt } if cmdMsg.Type != "call" { - // TcpPing 诊断命令异步执行,避免阻塞其他命令 // 其他状态变更命令保持同步,确保顺序执行 - if cmdMsg.Type == "TcpPing" { + if cmdMsg.Type == "TcpPing" || cmdMsg.Type == "UpgradeAgent" || cmdMsg.Type == "RollbackAgent" { go w.routeCommand(cmdMsg) } else { w.routeCommand(cmdMsg) @@ -502,9 +501,8 @@ func (w *WebSocketReporter) handleReceivedMessage(messageType int, message []byt return } if cmdMsg.Type != "call" { - // TcpPing 诊断命令异步执行,避免阻塞其他命令 // 其他状态变更命令保持同步,确保顺序执行 - if cmdMsg.Type == "TcpPing" { + if cmdMsg.Type == "TcpPing" || cmdMsg.Type == "UpgradeAgent" || cmdMsg.Type == "RollbackAgent" { go w.routeCommand(cmdMsg) } else { w.routeCommand(cmdMsg) diff --git a/vite-frontend/src/api/index.ts b/vite-frontend/src/api/index.ts index 9dd7cd8..846283d 100644 --- a/vite-frontend/src/api/index.ts +++ b/vite-frontend/src/api/index.ts @@ -42,9 +42,9 @@ export const checkNodeStatus = (nodeId?: number) => { }; export const upgradeNode = (id: number, version?: string) => - Network.post("/node/upgrade", { id, version: version || "" }); + Network.post("/node/upgrade", { id, version: version || "" }, { timeout: 5 * 60 * 1000 }); export const batchUpgradeNodes = (ids: number[], version?: string) => - Network.post("/node/batch-upgrade", { ids, version: version || "" }); + Network.post("/node/batch-upgrade", { ids, version: version || "" }, { timeout: 15 * 60 * 1000 }); export const getNodeReleases = () => Network.post("/node/releases"); export const rollbackNode = (id: number) => Network.post("/node/rollback", { id }); diff --git a/vite-frontend/src/api/network.ts b/vite-frontend/src/api/network.ts index 53486e9..d7af375 100644 --- a/vite-frontend/src/api/network.ts +++ b/vite-frontend/src/api/network.ts @@ -43,6 +43,10 @@ interface ApiResponse { data: T; } +interface RequestOptions { + timeout?: number; +} + // 处理token失效的逻辑 function handleTokenExpired() { // 清除localStorage中的token @@ -71,6 +75,7 @@ const Network = { get: function ( path: string = "", data: any = {}, + options: RequestOptions = {}, ): Promise> { return new Promise(function (resolve) { // 如果baseURL是默认值且是WebView环境,说明没有设置面板地址 @@ -83,7 +88,7 @@ const Network = { axios .get(path, { params: data, - timeout: 30000, + timeout: options.timeout ?? 30000, headers: { Authorization: window.localStorage.getItem("token"), }, @@ -117,6 +122,7 @@ const Network = { post: function ( path: string = "", data: any = {}, + options: RequestOptions = {}, ): Promise> { return new Promise(function (resolve) { // 如果baseURL是默认值且是WebView环境,说明没有设置面板地址 @@ -128,7 +134,7 @@ const Network = { axios .post(path, data, { - timeout: 30000, + timeout: options.timeout ?? 30000, headers: { Authorization: window.localStorage.getItem("token"), "Content-Type": "application/json",