修正frpc重启按钮的工作流程
CI / verify (push) Canceled after 0s

This commit is contained in:
2026-10-19 13:50:05 +08:00
parent 211d8e66e0
commit 2c1cf1260b
5 changed files with 195 additions and 7 deletions
+22 -6
View File
@@ -1,6 +1,7 @@
package api
import (
"context"
"encoding/json"
"errors"
"io"
@@ -961,20 +962,33 @@ func (h *FRPMultiHandler) DeleteProxy(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
}
// frpDetachedContext 给 frpc 的启停操作一个不随请求取消的上下文。
//
// 用户常常是从隧道那头点进来的(浏览器 → VPS → frpc → 本机),而「停止/重启」会先杀掉
// frpc —— 那一刻用户的连接就断了,r.Context() 随之取消。继续拿它做后续的数据库读写,
// 就会出现「frpc 停掉了、却再也拉不起来」的经典事故。
func frpDetachedContext(r *http.Request) (context.Context, context.CancelFunc) {
return context.WithTimeout(context.WithoutCancel(r.Context()), 2*time.Minute)
}
func (h *FRPMultiHandler) Start(w http.ResponseWriter, r *http.Request) {
if err := h.svc.Start(r.Context()); err != nil {
ctx, cancel := frpDetachedContext(r)
defer cancel()
if err := h.svc.Start(ctx); err != nil {
writeError(r, w, http.StatusBadRequest, err.Error())
return
}
writeJSON(w, http.StatusOK, h.svc.Status(r.Context()))
writeJSON(w, http.StatusOK, h.svc.Status(ctx))
}
func (h *FRPMultiHandler) Stop(w http.ResponseWriter, r *http.Request) {
if err := h.svc.Stop(r.Context()); err != nil {
ctx, cancel := frpDetachedContext(r)
defer cancel()
if err := h.svc.Stop(ctx); err != nil {
writeError(r, w, http.StatusBadRequest, err.Error())
return
}
writeJSON(w, http.StatusOK, h.svc.Status(r.Context()))
writeJSON(w, http.StatusOK, h.svc.Status(ctx))
}
func (h *FRPMultiHandler) Reload(w http.ResponseWriter, r *http.Request) {
@@ -987,11 +1001,13 @@ func (h *FRPMultiHandler) Reload(w http.ResponseWriter, r *http.Request) {
// Restart 重启全部 frpc:比「停止 → 启动」更稳,重启后会重建 Agent 隧道。
func (h *FRPMultiHandler) Restart(w http.ResponseWriter, r *http.Request) {
if err := h.svc.Restart(r.Context()); err != nil {
ctx, cancel := frpDetachedContext(r)
defer cancel()
if err := h.svc.Restart(ctx); err != nil {
writeError(r, w, http.StatusBadRequest, err.Error())
return
}
writeJSON(w, http.StatusOK, h.svc.Status(r.Context()))
writeJSON(w, http.StatusOK, h.svc.Status(ctx))
}
func (h *FRPMultiHandler) Logs(w http.ResponseWriter, r *http.Request) {