mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-01-13 01:02:46 +00:00
89 lines
2.4 KiB
Go
89 lines
2.4 KiB
Go
// Package job provides scheduled background jobs for the 3x-ui panel.
|
|
package job
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/mhsanaei/3x-ui/v2/database/model"
|
|
"github.com/mhsanaei/3x-ui/v2/logger"
|
|
"github.com/mhsanaei/3x-ui/v2/web/service"
|
|
"github.com/mhsanaei/3x-ui/v2/web/websocket"
|
|
)
|
|
|
|
// CheckNodeHealthJob periodically checks the health of all nodes in multi-node mode.
|
|
type CheckNodeHealthJob struct {
|
|
nodeService service.NodeService
|
|
}
|
|
|
|
// NewCheckNodeHealthJob creates a new job for checking node health.
|
|
func NewCheckNodeHealthJob() *CheckNodeHealthJob {
|
|
return &CheckNodeHealthJob{
|
|
nodeService: service.NodeService{},
|
|
}
|
|
}
|
|
|
|
// Run executes the health check for all nodes.
|
|
func (j *CheckNodeHealthJob) Run() {
|
|
// Check if multi-node mode is enabled
|
|
settingService := service.SettingService{}
|
|
multiMode, err := settingService.GetMultiNodeMode()
|
|
if err != nil || !multiMode {
|
|
return // Skip if multi-node mode is not enabled
|
|
}
|
|
|
|
nodes, err := j.nodeService.GetAllNodes()
|
|
if err != nil {
|
|
logger.Errorf("Failed to get nodes for health check: %v", err)
|
|
return
|
|
}
|
|
|
|
if len(nodes) == 0 {
|
|
return // No nodes to check
|
|
}
|
|
|
|
logger.Debugf("Checking health of %d nodes", len(nodes))
|
|
|
|
// Use a wait group to wait for all health checks to complete
|
|
var wg sync.WaitGroup
|
|
for _, node := range nodes {
|
|
n := node // Capture loop variable
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
if err := j.nodeService.CheckNodeHealth(n); err != nil {
|
|
logger.Debugf("[Node: %s] Health check failed: %v", n.Name, err)
|
|
} else {
|
|
logger.Debugf("[Node: %s] Status: %s, ResponseTime: %d ms", n.Name, n.Status, n.ResponseTime)
|
|
}
|
|
}()
|
|
}
|
|
|
|
// Wait for all checks to complete, then broadcast update
|
|
go func() {
|
|
wg.Wait()
|
|
// Get updated nodes with response times
|
|
updatedNodes, err := j.nodeService.GetAllNodes()
|
|
if err != nil {
|
|
logger.Warningf("Failed to get nodes for WebSocket broadcast: %v", err)
|
|
return
|
|
}
|
|
|
|
// Enrich nodes with assigned inbounds information
|
|
type NodeWithInbounds struct {
|
|
*model.Node
|
|
Inbounds []*model.Inbound `json:"inbounds,omitempty"`
|
|
}
|
|
|
|
result := make([]NodeWithInbounds, 0, len(updatedNodes))
|
|
for _, node := range updatedNodes {
|
|
inbounds, _ := j.nodeService.GetInboundsForNode(node.Id)
|
|
result = append(result, NodeWithInbounds{
|
|
Node: node,
|
|
Inbounds: inbounds,
|
|
})
|
|
}
|
|
|
|
// Broadcast via WebSocket
|
|
websocket.BroadcastNodes(result)
|
|
}()
|
|
}
|