优化ip=“” nodeid=0
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -24,6 +25,25 @@ var taskMutex sync.RWMutex
|
||||
var backendURL string
|
||||
var logger *zap.Logger
|
||||
|
||||
// 批量推送缓冲(每个任务一个缓冲)
|
||||
var pushBuffers = make(map[string]*pushBuffer)
|
||||
var bufferMutex sync.RWMutex
|
||||
|
||||
// pushBuffer 批量推送缓冲
|
||||
type pushBuffer struct {
|
||||
taskID string
|
||||
results []map[string]interface{}
|
||||
mu sync.Mutex
|
||||
lastPush time.Time
|
||||
pushTimer *time.Timer
|
||||
}
|
||||
|
||||
const (
|
||||
// 批量推送配置
|
||||
batchPushInterval = 1 * time.Second // 批量推送间隔:1秒
|
||||
batchPushMaxSize = 10 // 批量推送最大数量:10个结果
|
||||
)
|
||||
|
||||
func InitContinuousHandler(cfg *config.Config) {
|
||||
backendURL = cfg.Backend.URL
|
||||
logger, _ = zap.NewProduction()
|
||||
@@ -202,9 +222,6 @@ func pushResultToBackend(taskID string, result map[string]interface{}) {
|
||||
result["packet_loss"] = false
|
||||
}
|
||||
|
||||
// 推送结果到后端
|
||||
url := fmt.Sprintf("%s/api/public/node/continuous/result", backendURL)
|
||||
|
||||
// 优先使用心跳返回的节点信息
|
||||
nodeID := heartbeat.GetNodeID()
|
||||
nodeIP := heartbeat.GetNodeIP()
|
||||
@@ -215,22 +232,132 @@ func pushResultToBackend(taskID string, result map[string]interface{}) {
|
||||
logger.Debug("使用本地IP作为后备", zap.String("node_ip", nodeIP))
|
||||
}
|
||||
|
||||
// 发送 node_id 和 node_ip,后端可以通过这些信息精准匹配
|
||||
// 确保已经获取到 node_id,避免发送无效数据包
|
||||
if nodeID == 0 {
|
||||
logger.Warn("节点ID未获取,跳过推送结果",
|
||||
zap.String("task_id", taskID),
|
||||
zap.String("node_ip", nodeIP),
|
||||
zap.String("hint", "等待心跳返回node_id后再推送"))
|
||||
return
|
||||
}
|
||||
|
||||
// 确保已经获取到 node_ip
|
||||
if nodeIP == "" {
|
||||
logger.Warn("节点IP未获取,跳过推送结果",
|
||||
zap.String("task_id", taskID),
|
||||
zap.Uint("node_id", nodeID),
|
||||
zap.String("hint", "等待心跳返回node_ip后再推送"))
|
||||
return
|
||||
}
|
||||
|
||||
// 添加到批量推送缓冲
|
||||
addToPushBuffer(taskID, nodeID, nodeIP, result)
|
||||
}
|
||||
|
||||
// addToPushBuffer 添加结果到批量推送缓冲
|
||||
func addToPushBuffer(taskID string, nodeID uint, nodeIP string, result map[string]interface{}) {
|
||||
bufferMutex.Lock()
|
||||
buffer, exists := pushBuffers[taskID]
|
||||
if !exists {
|
||||
buffer = &pushBuffer{
|
||||
taskID: taskID,
|
||||
results: make([]map[string]interface{}, 0, batchPushMaxSize),
|
||||
lastPush: time.Now(),
|
||||
}
|
||||
pushBuffers[taskID] = buffer
|
||||
}
|
||||
bufferMutex.Unlock()
|
||||
|
||||
buffer.mu.Lock()
|
||||
defer buffer.mu.Unlock()
|
||||
|
||||
// 添加结果到缓冲
|
||||
buffer.results = append(buffer.results, result)
|
||||
|
||||
// 如果缓冲已满,立即推送
|
||||
shouldFlush := len(buffer.results) >= batchPushMaxSize
|
||||
buffer.mu.Unlock()
|
||||
|
||||
if shouldFlush {
|
||||
flushPushBuffer(taskID, nodeID, nodeIP)
|
||||
return
|
||||
}
|
||||
|
||||
buffer.mu.Lock()
|
||||
|
||||
// 如果距离上次推送超过间隔时间,启动定时器推送
|
||||
if buffer.pushTimer == nil {
|
||||
buffer.pushTimer = time.AfterFunc(batchPushInterval, func() {
|
||||
flushPushBuffer(taskID, nodeID, nodeIP)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// flushPushBuffer 刷新并推送缓冲中的结果
|
||||
func flushPushBuffer(taskID string, nodeID uint, nodeIP string) {
|
||||
bufferMutex.RLock()
|
||||
buffer, exists := pushBuffers[taskID]
|
||||
bufferMutex.RUnlock()
|
||||
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
|
||||
buffer.mu.Lock()
|
||||
if len(buffer.results) == 0 {
|
||||
buffer.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// 复制结果列表
|
||||
results := make([]map[string]interface{}, len(buffer.results))
|
||||
copy(results, buffer.results)
|
||||
buffer.results = buffer.results[:0] // 清空缓冲
|
||||
|
||||
// 停止定时器
|
||||
if buffer.pushTimer != nil {
|
||||
buffer.pushTimer.Stop()
|
||||
buffer.pushTimer = nil
|
||||
}
|
||||
|
||||
buffer.lastPush = time.Now()
|
||||
buffer.mu.Unlock()
|
||||
|
||||
// 批量推送结果(目前后端只支持单个结果,所以逐个推送)
|
||||
// 但可以减少HTTP请求的频率
|
||||
for _, result := range results {
|
||||
pushSingleResult(taskID, nodeID, nodeIP, result)
|
||||
}
|
||||
}
|
||||
|
||||
// pushSingleResult 推送单个结果到后端
|
||||
func pushSingleResult(taskID string, nodeID uint, nodeIP string, result map[string]interface{}) {
|
||||
// 推送结果到后端
|
||||
url := fmt.Sprintf("%s/api/public/node/continuous/result", backendURL)
|
||||
|
||||
// 获取节点位置信息
|
||||
country, province, city, isp := heartbeat.GetNodeLocation()
|
||||
|
||||
// 发送 node_id、node_ip 和位置信息,后端可以通过这些信息精准匹配
|
||||
data := map[string]interface{}{
|
||||
"task_id": taskID,
|
||||
"node_id": nodeID,
|
||||
"node_ip": nodeIP,
|
||||
"result": result,
|
||||
}
|
||||
|
||||
// 如果 node_id 存在,优先发送 node_id
|
||||
if nodeID > 0 {
|
||||
data["node_id"] = nodeID
|
||||
logger.Debug("推送结果时使用存储的node_id", zap.Uint("node_id", nodeID))
|
||||
// 添加位置信息(如果存在)
|
||||
if country != "" {
|
||||
data["country"] = country
|
||||
}
|
||||
|
||||
// 如果 node_ip 存在,发送 node_ip
|
||||
if nodeIP != "" {
|
||||
data["node_ip"] = nodeIP
|
||||
logger.Debug("推送结果时使用存储的node_ip", zap.String("node_ip", nodeIP))
|
||||
if province != "" {
|
||||
data["province"] = province
|
||||
}
|
||||
if city != "" {
|
||||
data["city"] = city
|
||||
}
|
||||
if isp != "" {
|
||||
data["isp"] = isp
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(data)
|
||||
@@ -261,18 +388,110 @@ func pushResultToBackend(taskID string, result map[string]interface{}) {
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
bodyStr := string(body)
|
||||
|
||||
// 检查是否是任务不存在的错误
|
||||
if containsTaskNotFoundError(bodyStr) {
|
||||
logger.Warn("后端任务不存在,停止节点端任务",
|
||||
zap.String("task_id", taskID),
|
||||
zap.String("response", bodyStr))
|
||||
// 停止对应的持续测试任务
|
||||
stopTaskByTaskID(taskID)
|
||||
return
|
||||
}
|
||||
|
||||
logger.Warn("推送结果失败,继续运行",
|
||||
zap.Int("status", resp.StatusCode),
|
||||
zap.String("task_id", taskID),
|
||||
zap.String("url", url),
|
||||
zap.String("response", string(body)))
|
||||
// 推送失败不停止任务,继续运行
|
||||
zap.String("response", bodyStr))
|
||||
// 其他错误不停止任务,继续运行
|
||||
return
|
||||
}
|
||||
|
||||
logger.Debug("推送结果成功", zap.String("task_id", taskID))
|
||||
}
|
||||
|
||||
// containsTaskNotFoundError 检查响应中是否包含任务不存在的错误
|
||||
func containsTaskNotFoundError(responseBody string) bool {
|
||||
// 检查常见的任务不存在错误消息
|
||||
errorKeywords := []string{
|
||||
"找不到对应的后端任务",
|
||||
"任务不存在",
|
||||
"task not found",
|
||||
"找不到对应的任务",
|
||||
}
|
||||
|
||||
responseLower := strings.ToLower(responseBody)
|
||||
for _, keyword := range errorKeywords {
|
||||
if strings.Contains(responseLower, strings.ToLower(keyword)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试解析 JSON 响应,检查错误消息
|
||||
var resp struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(responseBody), &resp); err == nil {
|
||||
msgLower := strings.ToLower(resp.Msg)
|
||||
for _, keyword := range errorKeywords {
|
||||
if strings.Contains(msgLower, strings.ToLower(keyword)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// stopTaskByTaskID 根据 taskID 停止对应的持续测试任务
|
||||
func stopTaskByTaskID(taskID string) {
|
||||
taskMutex.Lock()
|
||||
defer taskMutex.Unlock()
|
||||
|
||||
task, exists := continuousTasks[taskID]
|
||||
if !exists {
|
||||
logger.Debug("任务不存在,无需停止", zap.String("task_id", taskID))
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info("停止持续测试任务", zap.String("task_id", taskID))
|
||||
|
||||
// 停止任务
|
||||
task.IsRunning = false
|
||||
if task.pingTask != nil {
|
||||
task.pingTask.Stop()
|
||||
}
|
||||
if task.tcpingTask != nil {
|
||||
task.tcpingTask.Stop()
|
||||
}
|
||||
|
||||
// 关闭停止通道
|
||||
select {
|
||||
case <-task.StopCh:
|
||||
// 已经关闭
|
||||
default:
|
||||
close(task.StopCh)
|
||||
}
|
||||
|
||||
// 删除任务
|
||||
delete(continuousTasks, taskID)
|
||||
|
||||
// 清理推送缓冲
|
||||
bufferMutex.Lock()
|
||||
if buffer, exists := pushBuffers[taskID]; exists {
|
||||
if buffer.pushTimer != nil {
|
||||
buffer.pushTimer.Stop()
|
||||
}
|
||||
delete(pushBuffers, taskID)
|
||||
}
|
||||
bufferMutex.Unlock()
|
||||
|
||||
logger.Info("持续测试任务已停止", zap.String("task_id", taskID))
|
||||
}
|
||||
|
||||
func getLocalIP() string {
|
||||
// 简化实现:返回第一个非回环IP
|
||||
// 实际应该获取外网IP
|
||||
|
||||
Reference in New Issue
Block a user