Files
junhong_cmp_fiber/pkg/queue/handler.go
break 5c4d17e9fc
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
收口七月卡状态回调与系列授权兼容契约
完成运营商实名回调、业务事件观测序列与受控配置装配,同时恢复 UR43 已交付的 packages[].remove 字段及旧响应兼容,统一更新 OpenSpec、OpenAPI 和交付文档。

Constraint: 七月测试环境里程碑不新增或运行自动化测试

Rejected: 以必填 operation_type 替换 packages[].remove | 会破坏已交付前端契约

Confidence: high

Scope-risk: broad

Directive: 后续修改系列套餐管理接口必须保持 packages[].remove 和 ShopSeriesGrantResponse 兼容

Tested: go run ./cmd/gendocs;go build -buildvcs=false ./...;openspec validate complete-july-iteration-test-release --strict;git diff --check

Not-tested: 按本 Change 约定未运行 go test,真实运营商与 Gateway 联调延期
2026-07-24 19:59:24 +08:00

316 lines
12 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package queue
import (
"github.com/hibiken/asynq"
"github.com/redis/go-redis/v9"
"go.uber.org/zap"
"gorm.io/gorm"
"github.com/break/junhong_cmp_fiber/internal/exporter"
"github.com/break/junhong_cmp_fiber/internal/gateway"
"github.com/break/junhong_cmp_fiber/internal/infrastructure/integrationlog"
notification "github.com/break/junhong_cmp_fiber/internal/infrastructure/notification"
"github.com/break/junhong_cmp_fiber/internal/polling"
iot_card_svc "github.com/break/junhong_cmp_fiber/internal/service/iot_card"
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
"github.com/break/junhong_cmp_fiber/internal/task"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/storage"
)
type Handler struct {
mux *asynq.ServeMux
logger *zap.Logger
db *gorm.DB
redis *redis.Client
storage *storage.Service
gatewayClient *gateway.Client
pollingCallback task.PollingCallback
workerResult *WorkerBootstrapResult
asynqClient *asynq.Client
pollingBase *task.PollingBase
pollingStopResumeSvc iot_card_svc.StopResumeServiceInterface
}
func NewHandler(
db *gorm.DB,
redis *redis.Client,
storageSvc *storage.Service,
gatewayClient *gateway.Client,
pollingCallback task.PollingCallback,
workerResult *WorkerBootstrapResult,
asynqClient *asynq.Client,
logger *zap.Logger,
pollingBase *task.PollingBase,
pollingStopResumeSvc iot_card_svc.StopResumeServiceInterface,
) *Handler {
return &Handler{
mux: asynq.NewServeMux(),
logger: logger,
db: db,
redis: redis,
storage: storageSvc,
gatewayClient: gatewayClient,
pollingCallback: pollingCallback,
workerResult: workerResult,
asynqClient: asynqClient,
pollingBase: pollingBase,
pollingStopResumeSvc: pollingStopResumeSvc,
}
}
func (h *Handler) RegisterHandlers() *asynq.ServeMux {
emailHandler := task.NewEmailHandler(h.redis, h.logger)
h.mux.HandleFunc(constants.TaskTypeEmailSend, emailHandler.HandleEmailSend)
h.logger.Info("注册邮件发送任务处理器", zap.String("task_type", constants.TaskTypeEmailSend))
h.registerIotCardImportHandler()
h.registerDeviceImportHandler()
h.registerOrderPackageInvalidateHandler()
h.registerExportHandlers()
h.registerCommissionStatsHandlers()
h.registerCommissionCalculationHandler()
h.registerPollingHandlers()
h.registerCardObservationSeriesHandler()
h.registerPackageActivationHandlers()
h.registerOrderExpireHandler()
h.registerAlertCheckHandler()
h.registerDataCleanupHandler()
h.registerNotificationCleanupHandler()
h.registerAutoPurchaseHandler()
h.registerDailyTrafficFlushHandler()
h.logger.Info("所有任务处理器注册完成")
return h.mux
}
func (h *Handler) registerCardObservationSeriesHandler() {
handler := task.NewCardObservationSeriesHandler(h.workerResult.Services.CardObservationSeries, h.logger)
h.mux.HandleFunc(constants.TaskTypeCardObservationSeries, handler.Handle)
h.logger.Info("注册卡观测事件序列任务处理器", zap.String("task_type", constants.TaskTypeCardObservationSeries))
}
func (h *Handler) registerIotCardImportHandler() {
iotCardImportHandler := task.NewIotCardImportHandler(
h.db,
h.redis,
h.workerResult.Stores.IotCardImportTask,
h.workerResult.Stores.IotCard,
h.workerResult.Stores.AssetWallet,
h.storage,
h.pollingCallback,
h.logger,
)
h.mux.HandleFunc(constants.TaskTypeIotCardImport, iotCardImportHandler.HandleIotCardImport)
h.logger.Info("注册 IoT 卡导入任务处理器", zap.String("task_type", constants.TaskTypeIotCardImport))
}
func (h *Handler) registerOrderPackageInvalidateHandler() {
orderPkgHandler := task.NewOrderPackageInvalidateHandler(
h.workerResult.Stores.OrderPackageInvalidateTask,
h.workerResult.Stores.Order,
h.workerResult.Stores.PackageUsage,
h.storage,
h.logger,
)
h.mux.HandleFunc(constants.TaskTypeOrderPackageInvalidate, orderPkgHandler.Handle)
h.logger.Info("注册订单套餐批量失效任务处理器", zap.String("task_type", constants.TaskTypeOrderPackageInvalidate))
}
func (h *Handler) registerDeviceImportHandler() {
deviceImportHandler := task.NewDeviceImportHandler(
h.db,
h.redis,
h.workerResult.Stores.DeviceImportTask,
h.workerResult.Stores.Device,
h.workerResult.Stores.DeviceSimBinding,
h.workerResult.Stores.IotCard,
h.workerResult.Stores.AssetWallet,
h.workerResult.Stores.AssetIdentifier,
h.storage,
h.logger,
)
h.mux.HandleFunc(constants.TaskTypeDeviceImport, deviceImportHandler.HandleDeviceImport)
h.logger.Info("注册设备导入任务处理器", zap.String("task_type", constants.TaskTypeDeviceImport))
}
func (h *Handler) registerExportHandlers() {
sceneRegistry := exporter.NewDefaultRegistry(h.db)
dispatchHandler := task.NewExportDispatchHandler(
h.db,
h.redis,
h.workerResult.Stores.ExportTask,
h.workerResult.Stores.ExportShardTask,
h.asynqClient,
sceneRegistry,
h.logger,
)
shardHandler := task.NewExportShardHandler(
h.redis,
h.workerResult.Stores.ExportTask,
h.workerResult.Stores.ExportShardTask,
h.asynqClient,
h.storage,
sceneRegistry,
h.logger,
)
finalizeHandler := task.NewExportFinalizeHandler(
h.redis,
h.workerResult.Stores.ExportTask,
h.workerResult.Stores.ExportShardTask,
h.storage,
sceneRegistry,
h.logger,
)
h.mux.HandleFunc(constants.TaskTypeExportDispatch, dispatchHandler.HandleExportDispatch)
h.logger.Info("注册导出 dispatch 任务处理器", zap.String("task_type", constants.TaskTypeExportDispatch))
h.mux.HandleFunc(constants.TaskTypeExportShard, shardHandler.HandleExportShard)
h.logger.Info("注册导出 shard 任务处理器", zap.String("task_type", constants.TaskTypeExportShard))
h.mux.HandleFunc(constants.TaskTypeExportFinalize, finalizeHandler.HandleExportFinalize)
h.logger.Info("注册导出 finalize 任务处理器", zap.String("task_type", constants.TaskTypeExportFinalize))
}
func (h *Handler) registerCommissionStatsHandlers() {
updateHandler := task.NewCommissionStatsUpdateHandler(
h.redis,
h.workerResult.Stores.ShopSeriesCommissionStats,
h.workerResult.Stores.ShopPackageAllocation,
h.logger,
)
syncHandler := task.NewCommissionStatsSyncHandler(
h.db,
h.redis,
h.workerResult.Stores.ShopSeriesCommissionStats,
h.logger,
)
archiveHandler := task.NewCommissionStatsArchiveHandler(
h.db,
h.redis,
h.workerResult.Stores.ShopSeriesCommissionStats,
h.logger,
)
h.mux.HandleFunc(constants.TaskTypeCommissionStatsUpdate, updateHandler.HandleCommissionStatsUpdate)
h.logger.Info("注册佣金统计更新任务处理器", zap.String("task_type", constants.TaskTypeCommissionStatsUpdate))
h.mux.HandleFunc(constants.TaskTypeCommissionStatsSync, syncHandler.HandleCommissionStatsSync)
h.logger.Info("注册佣金统计同步任务处理器", zap.String("task_type", constants.TaskTypeCommissionStatsSync))
h.mux.HandleFunc(constants.TaskTypeCommissionStatsArchive, archiveHandler.HandleCommissionStatsArchive)
h.logger.Info("注册佣金统计归档任务处理器", zap.String("task_type", constants.TaskTypeCommissionStatsArchive))
}
func (h *Handler) registerCommissionCalculationHandler() {
commissionCalculationHandler := task.NewCommissionCalculationHandler(
h.db,
h.workerResult.Services.CommissionCalculation,
h.logger,
)
h.mux.HandleFunc(constants.TaskTypeCommission, commissionCalculationHandler.HandleCommissionCalculation)
h.logger.Info("注册佣金计算任务处理器", zap.String("task_type", constants.TaskTypeCommission))
}
func (h *Handler) registerPollingHandlers() {
integrationRepository := integrationlog.NewRepository(h.db)
realnameHandler := task.NewPollingRealnameHandler(
h.pollingBase, h.gatewayClient, h.workerResult.Services.CardObservation, integrationRepository)
carrierStore := postgres.NewCarrierStore(h.db)
carddataHandler := task.NewPollingCarddataHandler(
h.pollingBase, h.gatewayClient, carrierStore, h.workerResult.Services.CardObservation, integrationRepository)
packageHandler := task.NewPollingPackageHandler(
h.pollingBase, h.workerResult.Stores.IotCard,
h.pollingStopResumeSvc)
protectHandler := task.NewPollingProtectHandler(
h.db, h.workerResult.Services.ObservationSeriesEvents,
h.pollingBase, h.gatewayClient, h.workerResult.Stores.IotCard,
h.workerResult.Stores.DeviceSimBinding, h.pollingStopResumeSvc)
cardStatusHandler := task.NewPollingCardStatusHandler(
h.pollingBase, h.gatewayClient, h.workerResult.Services.CardObservation, integrationRepository)
h.mux.HandleFunc(constants.TaskTypePollingRealname, realnameHandler.Handle)
h.mux.HandleFunc(constants.TaskTypePollingCarddata, carddataHandler.Handle)
h.mux.HandleFunc(constants.TaskTypePollingPackage, packageHandler.Handle)
h.mux.HandleFunc(constants.TaskTypePollingProtect, protectHandler.Handle)
h.mux.HandleFunc(constants.TaskTypePollingCardStatus, cardStatusHandler.Handle)
h.logger.Info("已注册轮询任务处理器realname/carddata/package/protect/card_status")
}
func (h *Handler) registerPackageActivationHandlers() {
packageActivationHandler := polling.NewPackageActivationHandler(
h.db,
h.redis,
h.asynqClient,
h.workerResult.Services.ActivationService,
nil,
h.logger,
)
h.mux.HandleFunc(constants.TaskTypePackageFirstActivation, packageActivationHandler.HandlePackageFirstActivation)
h.logger.Info("注册首次实名激活任务处理器", zap.String("task_type", constants.TaskTypePackageFirstActivation))
h.mux.HandleFunc(constants.TaskTypePackageQueueActivation, packageActivationHandler.HandlePackageQueueActivation)
h.logger.Info("注册排队激活任务处理器", zap.String("task_type", constants.TaskTypePackageQueueActivation))
}
func (h *Handler) registerOrderExpireHandler() {
orderExpireHandler := task.NewOrderExpireHandler(h.workerResult.Services.OrderExpirer, h.logger)
h.mux.HandleFunc(constants.TaskTypeOrderExpire, orderExpireHandler.HandleOrderExpire)
h.logger.Info("注册订单超时取消任务处理器", zap.String("task_type", constants.TaskTypeOrderExpire))
}
func (h *Handler) registerAlertCheckHandler() {
alertCheckHandler := task.NewAlertCheckHandler(h.workerResult.Services.AlertService, h.logger)
h.mux.HandleFunc(constants.TaskTypeAlertCheck, alertCheckHandler.HandleAlertCheck)
h.logger.Info("注册告警检查任务处理器", zap.String("task_type", constants.TaskTypeAlertCheck))
}
func (h *Handler) registerDataCleanupHandler() {
dataCleanupHandler := task.NewDataCleanupHandler(h.workerResult.Services.CleanupService, h.logger)
h.mux.HandleFunc(constants.TaskTypeDataCleanup, dataCleanupHandler.HandleDataCleanup)
h.logger.Info("注册数据清理任务处理器", zap.String("task_type", constants.TaskTypeDataCleanup))
}
func (h *Handler) registerNotificationCleanupHandler() {
cleanupService := notification.NewCleanupService(h.db, h.logger)
cleanupHandler := task.NewNotificationCleanupHandler(cleanupService, h.logger)
h.mux.HandleFunc(constants.TaskTypeNotificationCleanup, cleanupHandler.Handle)
h.logger.Info("注册站内通知保留清理任务处理器", zap.String("task_type", constants.TaskTypeNotificationCleanup))
}
func (h *Handler) registerAutoPurchaseHandler() {
autoPurchaseHandler := task.NewAutoPurchaseHandler(
h.db,
h.workerResult.Stores.Order,
nil, // RechargeOrderStore在 NewAutoPurchaseHandler 内按需初始化
nil, // PaymentStore在 NewAutoPurchaseHandler 内按需初始化
h.workerResult.Stores.AssetWallet,
nil, // AssetWalletTransactionStore在 NewAutoPurchaseHandler 内按需初始化
h.workerResult.Stores.PackageUsage,
h.redis,
h.asynqClient,
h.logger,
h.workerResult.Services.ObservationSeriesEvents,
)
h.mux.HandleFunc(constants.TaskTypeAutoPurchaseAfterRecharge, autoPurchaseHandler.ProcessTask)
h.logger.Info("注册自动购包任务处理器", zap.String("task_type", constants.TaskTypeAutoPurchaseAfterRecharge))
}
func (h *Handler) registerDailyTrafficFlushHandler() {
cardDailyUsageStore := postgres.NewCardDailyUsageStore(h.db)
dailyTrafficFlushHandler := task.NewDailyTrafficFlushHandler(h.redis, cardDailyUsageStore, h.logger)
h.mux.HandleFunc(constants.TaskTypeDailyTrafficFlush, dailyTrafficFlushHandler.HandleDailyTrafficFlush)
h.logger.Info("注册每日流量落盘任务处理器", zap.String("task_type", constants.TaskTypeDailyTrafficFlush))
}
// GetMux 获取 ServeMux用于启动 Worker 服务器)
func (h *Handler) GetMux() *asynq.ServeMux {
return h.mux
}