Files
junhong_cmp_fiber/internal/handler/admin/polling_monitoring.go
huang 931e140e8e
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m35s
feat: 实现 IoT 卡轮询系统(支持千万级卡规模)
实现功能:
- 实名状态检查轮询(可配置间隔)
- 卡流量检查轮询(支持跨月流量追踪)
- 套餐检查与超额自动停机
- 分布式并发控制(Redis 信号量)
- 手动触发轮询(单卡/批量/条件筛选)
- 数据清理配置与执行
- 告警规则与历史记录
- 实时监控统计(队列/性能/并发)

性能优化:
- Redis 缓存卡信息,减少 DB 查询
- Pipeline 批量写入 Redis
- 异步流量记录写入
- 渐进式初始化(10万卡/批)

压测工具(scripts/benchmark/):
- Mock Gateway 模拟上游服务
- 测试卡生成器
- 配置初始化脚本
- 实时监控脚本

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:32:44 +08:00

140 lines
4.3 KiB
Go

package admin
import (
"github.com/gofiber/fiber/v2"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
"github.com/break/junhong_cmp_fiber/internal/service/polling"
"github.com/break/junhong_cmp_fiber/pkg/response"
)
// PollingMonitoringHandler 轮询监控处理器
type PollingMonitoringHandler struct {
service *polling.MonitoringService
}
// NewPollingMonitoringHandler 创建轮询监控处理器
func NewPollingMonitoringHandler(service *polling.MonitoringService) *PollingMonitoringHandler {
return &PollingMonitoringHandler{service: service}
}
// GetOverview 获取轮询总览
// @Summary 获取轮询总览统计
// @Description 获取轮询系统的总览统计数据,包括初始化进度、队列大小等
// @Tags 轮询管理-监控
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {object} response.Response{data=dto.PollingOverviewResp}
// @Router /api/admin/polling-stats [get]
func (h *PollingMonitoringHandler) GetOverview(c *fiber.Ctx) error {
ctx := c.UserContext()
stats, err := h.service.GetOverview(ctx)
if err != nil {
return err
}
return response.Success(c, &dto.PollingOverviewResp{
TotalCards: stats.TotalCards,
InitializedCards: stats.InitializedCards,
InitProgress: stats.InitProgress,
IsInitializing: stats.IsInitializing,
RealnameQueueSize: stats.RealnameQueueSize,
CarddataQueueSize: stats.CarddataQueueSize,
PackageQueueSize: stats.PackageQueueSize,
})
}
// GetQueueStatuses 获取队列状态
// @Summary 获取轮询队列状态
// @Description 获取所有轮询队列的详细状态,包括队列大小、到期数、等待时间等
// @Tags 轮询管理-监控
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {object} response.Response{data=dto.PollingQueueStatusListResp}
// @Router /api/admin/polling-stats/queues [get]
func (h *PollingMonitoringHandler) GetQueueStatuses(c *fiber.Ctx) error {
ctx := c.UserContext()
statuses, err := h.service.GetQueueStatuses(ctx)
if err != nil {
return err
}
items := make([]*dto.PollingQueueStatusResp, 0, len(statuses))
for _, s := range statuses {
items = append(items, &dto.PollingQueueStatusResp{
TaskType: s.TaskType,
TaskTypeName: s.TaskTypeName,
QueueSize: s.QueueSize,
ManualPending: s.ManualPending,
DueCount: s.DueCount,
AvgWaitTime: s.AvgWaitTime,
})
}
return response.Success(c, &dto.PollingQueueStatusListResp{Items: items})
}
// GetTaskStatuses 获取任务统计
// @Summary 获取轮询任务统计
// @Description 获取所有轮询任务类型的执行统计,包括成功率、平均耗时等
// @Tags 轮询管理-监控
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {object} response.Response{data=dto.PollingTaskStatsListResp}
// @Router /api/admin/polling-stats/tasks [get]
func (h *PollingMonitoringHandler) GetTaskStatuses(c *fiber.Ctx) error {
ctx := c.UserContext()
statuses, err := h.service.GetTaskStatuses(ctx)
if err != nil {
return err
}
items := make([]*dto.PollingTaskStatsResp, 0, len(statuses))
for _, s := range statuses {
items = append(items, &dto.PollingTaskStatsResp{
TaskType: s.TaskType,
TaskTypeName: s.TaskTypeName,
SuccessCount1h: s.SuccessCount1h,
FailureCount1h: s.FailureCount1h,
TotalCount1h: s.TotalCount1h,
SuccessRate: s.SuccessRate,
AvgDurationMs: s.AvgDurationMs,
})
}
return response.Success(c, &dto.PollingTaskStatsListResp{Items: items})
}
// GetInitProgress 获取初始化进度
// @Summary 获取轮询初始化进度
// @Description 获取轮询系统初始化的详细进度,包括已处理数、预计完成时间等
// @Tags 轮询管理-监控
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {object} response.Response{data=dto.PollingInitProgressResp}
// @Router /api/admin/polling-stats/init-progress [get]
func (h *PollingMonitoringHandler) GetInitProgress(c *fiber.Ctx) error {
ctx := c.UserContext()
progress, err := h.service.GetInitProgress(ctx)
if err != nil {
return err
}
return response.Success(c, &dto.PollingInitProgressResp{
TotalCards: progress.TotalCards,
InitializedCards: progress.InitializedCards,
Progress: progress.Progress,
IsComplete: progress.IsComplete,
StartedAt: progress.StartedAt,
EstimatedETA: progress.EstimatedETA,
})
}