feat: 卡流量读数先过采集队列再入账,扣减按采集时刻确定套餐
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m27s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m27s
- 每卡 Redis 采集队列(默认 N=3、跨天清空、回退容差 1 MB),攒满且不下降才写最后一个点 - 测试环境全量切换日快照计量,下线灰度名单、切换水位与卡表基线扣费;全部卡置待建起点 - 读数区分没给值与 0;有套餐的卡读数 0 也写快照与日用量 0 行;重置日比较基准为 0 照常防旧值 - 新增采集记录(按月分区保留 90 天)、人工冲正流水与后台接口、采集告警 - 扣减按采集时刻有效套餐查找,只对生效中套餐做状态迁移,查不到套餐按成功跳过 - 换货新卡(新设备下的卡)打待建起点;采集间隔上限只校验启用中的轮询配置 Change: add-card-traffic-queue-and-observed-deduction Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,7 @@ import (
|
||||
refundchannelApp "github.com/break/junhong_cmp_fiber/internal/application/refundchannel"
|
||||
walletApp "github.com/break/junhong_cmp_fiber/internal/application/wallet"
|
||||
"github.com/break/junhong_cmp_fiber/internal/bootstrap"
|
||||
"github.com/break/junhong_cmp_fiber/internal/domain/cardflow"
|
||||
"github.com/break/junhong_cmp_fiber/internal/gateway"
|
||||
approvalInfra "github.com/break/junhong_cmp_fiber/internal/infrastructure/approval"
|
||||
assetAutoRenewalInfra "github.com/break/junhong_cmp_fiber/internal/infrastructure/assetautorenewal"
|
||||
@@ -173,6 +174,7 @@ func runWorker(cfg *config.Config) {
|
||||
|
||||
if runsSingletonModules(cfg.Worker.Role) {
|
||||
pollingInitializer = startPollingInitializer(ctx, runtime, appLogger)
|
||||
startTrafficCollectionPartitionMaintainer(ctx, runtime, appLogger)
|
||||
pollingScheduler = startPollingScheduler(ctx, runtime, pollingInitializer, appLogger)
|
||||
asynqScheduler = startAsynqScheduler(cfg, runtime.redisAddr, appLogger)
|
||||
}
|
||||
@@ -858,6 +860,43 @@ func startOutboxRelay(ctx context.Context, runtime *workerRuntime, instanceName
|
||||
appLogger.Info("Outbox Relay 已启动", zap.String("lease_owner", owner))
|
||||
}
|
||||
|
||||
// startTrafficCollectionPartitionMaintainer 为 leader/all 维护卡流量采集记录月分区并扫描采集告警:
|
||||
// 每 12 小时预建本月起 2 个月的分区、删除整月都早于保留期的分区;每天扫描一次前一天的采集告警。
|
||||
func startTrafficCollectionPartitionMaintainer(ctx context.Context, runtime *workerRuntime, appLogger *zap.Logger) {
|
||||
store := postgres.NewCardTrafficCollectionStore(runtime.db)
|
||||
alerts := cardObservationInfra.NewTrafficAlertScanner(runtime.db, appLogger)
|
||||
go func() {
|
||||
ticker := time.NewTicker(time.Hour)
|
||||
defer ticker.Stop()
|
||||
var lastMaintained time.Time
|
||||
var lastScannedDay string
|
||||
for {
|
||||
now := time.Now()
|
||||
if now.Sub(lastMaintained) >= 12*time.Hour {
|
||||
if err := store.MaintainPartitions(ctx, now, 2, constants.TrafficCollectionRetentionDays); err != nil && ctx.Err() == nil {
|
||||
appLogger.Error("维护卡流量采集记录分区失败", zap.Error(err))
|
||||
} else {
|
||||
lastMaintained = now
|
||||
}
|
||||
}
|
||||
// 每天扫描一次前一天(上海日期)的采集告警。
|
||||
yesterday := cardflow.ShanghaiDate(now).AddDate(0, 0, -1)
|
||||
if day := yesterday.Format("2006-01-02"); day != lastScannedDay {
|
||||
if err := alerts.Scan(ctx, yesterday); err != nil && ctx.Err() == nil {
|
||||
appLogger.Error("扫描卡流量采集告警失败", zap.Error(err))
|
||||
} else {
|
||||
lastScannedDay = day
|
||||
}
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// startPollingInitializer 为 leader/all 启动渐进式初始化器,并保留配置变更重启逻辑。
|
||||
func startPollingInitializer(ctx context.Context, runtime *workerRuntime, appLogger *zap.Logger) *polling.PollingInitializer {
|
||||
pollingInitializer := polling.NewPollingInitializer(
|
||||
|
||||
Reference in New Issue
Block a user