143 lines
3.2 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|
|
}
|