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) } } } }