fix(watchdog): now the client could successfully send more msgs to watchdog instead of the only connection msg

- Add debug logging for watchdog operations
- Standardize message format for instance operations
- Improve TCP message handling with proper line termination
- Enhance error handling in watchdog operations
- Add proper cleanup of recvChan in sendMsg
- Update response handling in instance handlers
This commit is contained in:
2026-04-07 23:29:07 +08:00
parent 37c10f1c07
commit 2426933f49
3 changed files with 102 additions and 63 deletions
+17 -4
View File
@@ -627,7 +627,11 @@ func StartInstanceHandler(w http.ResponseWriter, r *http.Request) {
} }
if is.watchdogConnected { if is.watchdogConnected {
watchdog.AddInstance(serviceName) if !watchdog.AddInstance(serviceName) {
postLog.Warning(fmt.Sprintf("[StartInstanceHandler] Failed to add watchdog instance %s", serviceName))
SendSuccessResponse(w, "Instance started successfully but watchdog instance add failed", nil)
return
}
} }
SendSuccessResponse(w, "Instance started successfully", nil) SendSuccessResponse(w, "Instance started successfully", nil)
@@ -702,7 +706,7 @@ func StopInstanceHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
postLog.Info(fmt.Sprintf("[StopInstanceHandler] Windows service %s stopped successfully", serviceName)) postLog.Info(fmt.Sprintf("[StopInstanceHandler] Windows service %s stopped successfully", serviceName))
SendSuccessResponse(w, "Instance stopped successfully", nil) // SendSuccessResponse(w, "Instance stopped successfully", nil)
case "systemd": case "systemd":
if err := StopSystemdService(serviceName); err != nil { if err := StopSystemdService(serviceName); err != nil {
@@ -711,7 +715,7 @@ func StopInstanceHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
postLog.Info(fmt.Sprintf("[StopInstanceHandler] Systemd service %s stopped successfully", serviceName)) postLog.Info(fmt.Sprintf("[StopInstanceHandler] Systemd service %s stopped successfully", serviceName))
SendSuccessResponse(w, "Instance stopped successfully", nil) // SendSuccessResponse(w, "Instance stopped successfully", nil)
case "init.d": case "init.d":
if err := StopInitDService(serviceName); err != nil { if err := StopInitDService(serviceName); err != nil {
@@ -720,13 +724,22 @@ func StopInstanceHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
postLog.Info(fmt.Sprintf("[StopInstanceHandler] Init.d service %s stopped successfully", serviceName)) postLog.Info(fmt.Sprintf("[StopInstanceHandler] Init.d service %s stopped successfully", serviceName))
SendSuccessResponse(w, "Instance stopped successfully", nil) // SendSuccessResponse(w, "Instance stopped successfully", nil)
default: default:
postLog.Error(fmt.Sprintf("[StopInstanceHandler] Unsupported init system: %s", initType)) postLog.Error(fmt.Sprintf("[StopInstanceHandler] Unsupported init system: %s", initType))
SendErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Unsupported init system: %s", initType)) SendErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Unsupported init system: %s", initType))
return return
} }
if is.watchdogConnected {
if !watchdog.RemoveInstance(serviceName) {
postLog.Warning(fmt.Sprintf("[StopInstanceHandler] Failed to remove watchdog instance %s", serviceName))
SendSuccessResponse(w, "Instance stopped successfully but watchdog instance remove failed", nil)
} else {
SendSuccessResponse(w, "Instance stopped successfully", nil)
}
}
} }
func RestartInstanceHandler(w http.ResponseWriter, r *http.Request) { func RestartInstanceHandler(w http.ResponseWriter, r *http.Request) {
+30 -4
View File
@@ -2,23 +2,45 @@ package watchdog
import ( import (
"fmt" "fmt"
"super-frpc/postLog"
) )
func AddInstance(serviceName string) bool { func AddInstance(serviceName string) bool {
postLog.Debug(fmt.Sprintf("[watchdog] Add service monitor: %s", serviceName))
if !IsConnected() { if !IsConnected() {
return false return false
} }
message := fmt.Sprintf("[instance.add] <serviceName>%s</serviceName>", serviceName) message := fmt.Sprintf("[monitor.add] <serviceName>%s</serviceName>", serviceName)
response, err := sendMsg(message, 3) response, err := sendMsg(message, 3)
if err != nil { if err != nil {
return false return false
} else if response == "success" {
return true
} }
return response == "success" return false
} }
func RemoveInstance(serviceName string) bool { func RemoveInstance(serviceName string) bool {
postLog.Debug(fmt.Sprintf("[watchdog] Remove service monitor: %s", serviceName))
if !IsConnected() {
return false
}
message := fmt.Sprintf("[monitor.remove] <serviceName>%s</serviceName>", serviceName)
response, err := sendMsg(message, 3)
if err != nil {
return false
} else if response == "success" {
return true
}
return false
}
func CloseInstance(serviceName string) bool {
postLog.Debug(fmt.Sprintf("[watchdog] Remove service monitor: %s", serviceName))
if !IsConnected() { if !IsConnected() {
return false return false
} }
@@ -27,9 +49,11 @@ func RemoveInstance(serviceName string) bool {
response, err := sendMsg(message, 3) response, err := sendMsg(message, 3)
if err != nil { if err != nil {
return false return false
} else if response == "success" {
return true
} }
return response == "success" return false
} }
func Close() bool { func Close() bool {
@@ -41,7 +65,9 @@ func Close() bool {
response, err := sendMsg(message, 3) response, err := sendMsg(message, 3)
if err != nil { if err != nil {
return false return false
} else if response == "success" {
return true
} }
return response == "success" return false
} }
+51 -51
View File
@@ -4,10 +4,10 @@ import (
"bufio" "bufio"
"fmt" "fmt"
"net" "net"
"strings"
"super-frpc/postLog" "super-frpc/postLog"
"sync" "sync"
"time" "time"
"strings"
) )
var ( var (
@@ -57,7 +57,7 @@ func tcpConnect(ipaddr string, port int) error {
return nil return nil
} }
func sendMsg(message string, target int) (string, error) { func sendMsg(message string, timeout int) (string, error) {
tcpConnMutex.Lock() tcpConnMutex.Lock()
if tcpConn == nil { if tcpConn == nil {
@@ -65,7 +65,7 @@ func sendMsg(message string, target int) (string, error) {
return "", fmt.Errorf("not connected") return "", fmt.Errorf("not connected")
} }
_, err := tcpConn.Write([]byte(message)) _, err := tcpConn.Write([]byte(message + "\n"))
if err != nil { if err != nil {
tcpConnMutex.Unlock() tcpConnMutex.Unlock()
return "", fmt.Errorf("failed to send message: %v", err) return "", fmt.Errorf("failed to send message: %v", err)
@@ -75,68 +75,68 @@ func sendMsg(message string, target int) (string, error) {
select { select {
case response := <-recvChan: case response := <-recvChan:
return response, nil for len(recvChan) > 0 {
case <-time.After(time.Duration(target) * time.Second): <-recvChan
}
return strings.TrimSpace(response), nil
case <-time.After(time.Duration(timeout) * time.Second):
return "", fmt.Errorf("timeout waiting for response") return "", fmt.Errorf("timeout waiting for response")
} }
} }
func recvMsg() { func recvMsg() {
defer recvWg.Done() defer recvWg.Done()
tcpConnMutex.Lock() tcpConnMutex.Lock()
if tcpConn == nil { if tcpConn == nil {
tcpConnMutex.Unlock() tcpConnMutex.Unlock()
return return
} }
conn := tcpConn conn := tcpConn
tcpConnMutex.Unlock() tcpConnMutex.Unlock()
reader := bufio.NewReader(conn) reader := bufio.NewReader(conn)
for { for {
select { select {
case <-stopRecvChan: case <-stopRecvChan:
return return
default: default:
conn.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) conn.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
// ⭐ 改为读取到换行符 \n 为止 data, err := reader.ReadBytes('\n')
data, err := reader.ReadBytes('\n')
if len(data) > 0 { if len(data) > 0 {
// ⭐ 用 strings.TrimSpace 去掉末尾的 \n line := strings.TrimSpace(string(data))
line := strings.TrimSpace(string(data))
if len(line) > 0 { if len(line) > 0 {
select { select {
case recvChan <- line: case recvChan <- line:
default: default:
} }
if !isResponseMessage(line) { if !isResponseMessage(line) {
postLog.Debug(fmt.Sprintf("[Watchdog] TCP Socket received message: %s", line)) postLog.Debug(fmt.Sprintf("[Watchdog] TCP Socket received message: %s", line))
} }
} }
} }
if err != nil { if err != nil {
if netErr, ok := err.(net.Error); ok && netErr.Timeout() { if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
continue continue
} }
// 处理非超时的严重错误(如服务端断开) tcpConnMutex.Lock()
tcpConnMutex.Lock() if tcpConn != nil {
if tcpConn != nil { tcpConn.Close()
tcpConn.Close() tcpConn = nil
tcpConn = nil isConnected = false
isConnected = false }
} tcpConnMutex.Unlock()
tcpConnMutex.Unlock() return
return }
} }
} }
}
} }
func isResponseMessage(msg string) bool { func isResponseMessage(msg string) bool {