2025-03-27 16:27:41 +08:00

143 lines
3.2 KiB
Go

package docker
import (
"context"
"log"
"sync"
"time"
"gorm.io/gorm"
"gitee.ltd/lxh/wechat-robot/internal/model"
)
// ContainerMonitor 容器监控器
type ContainerMonitor struct {
db *gorm.DB
interval time.Duration
robots map[string]struct{} // 记录正在监控的机器人容器ID
mutex sync.RWMutex
stopChan chan struct{}
monitorActive bool
}
// NewContainerMonitor 创建容器监控器
func NewContainerMonitor(db *gorm.DB, interval time.Duration) *ContainerMonitor {
if interval == 0 {
interval = 30 * time.Second // 默认30秒检查一次
}
return &ContainerMonitor{
db: db,
interval: interval,
robots: make(map[string]struct{}),
stopChan: make(chan struct{}),
}
}
// Start 启动监控
func (m *ContainerMonitor) Start(ctx context.Context) {
m.mutex.Lock()
if m.monitorActive {
m.mutex.Unlock()
return
}
m.monitorActive = true
m.mutex.Unlock()
log.Println("Starting container monitor...")
// 启动监控协程
go func() {
ticker := time.NewTicker(m.interval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
m.checkRobots(context.Background())
case <-m.stopChan:
log.Println("Container monitor stopped")
return
case <-ctx.Done():
log.Println("Container monitor stopped due to context cancellation")
return
}
}
}()
}
// Stop 停止监控
func (m *ContainerMonitor) Stop() {
m.mutex.Lock()
defer m.mutex.Unlock()
if m.monitorActive {
close(m.stopChan)
m.monitorActive = false
}
}
// AddRobot 添加机器人到监控列表
func (m *ContainerMonitor) AddRobot(containerID string) {
m.mutex.Lock()
defer m.mutex.Unlock()
m.robots[containerID] = struct{}{}
}
// RemoveRobot 从监控列表中移除机器人
func (m *ContainerMonitor) RemoveRobot(containerID string) {
m.mutex.Lock()
defer m.mutex.Unlock()
delete(m.robots, containerID)
}
// checkRobots 检查所有机器人状态
func (m *ContainerMonitor) checkRobots(ctx context.Context) {
m.mutex.RLock()
robotIDs := make([]string, 0, len(m.robots))
for id := range m.robots {
robotIDs = append(robotIDs, id)
}
m.mutex.RUnlock()
for _, containerID := range robotIDs {
// 使用新的上下文,避免一个检查失败影响其他检查
checkCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
// 获取机器人的当前状态
status, errMsg, err := GetWechatBotStatus(checkCtx, containerID)
if err != nil {
log.Printf("Error checking robot %s: %v", containerID, err)
continue
}
// 更新数据库中的状态
robot := &model.Robot{}
result := m.db.Where("container_id = ?", containerID).First(robot)
if result.Error != nil {
log.Printf("Error finding robot %s in database: %v", containerID, result.Error)
continue
}
// 只有状态变化时才更新
if robot.Status != status {
robot.Status = status
robot.ErrorMessage = errMsg
// 如果状态变为在线,更新登录时间
if status == model.RobotStatusOnline {
now := time.Now()
robot.LastLoginAt = &now
}
if err := m.db.Save(robot).Error; err != nil {
log.Printf("Error updating robot %s status: %v", containerID, err)
} else {
log.Printf("Robot %s status updated to %s", containerID, status)
}
}
}
}