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>
65 lines
2.6 KiB
Go
65 lines
2.6 KiB
Go
package polling
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"time"
|
||
|
||
"gorm.io/gorm"
|
||
|
||
"github.com/break/junhong_cmp_fiber/internal/domain/cardflow"
|
||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||
)
|
||
|
||
// TrafficQueueLimits 是校验流量采集间隔需要的采集队列配置。
|
||
type TrafficQueueLimits struct {
|
||
Size int
|
||
ClearOnNewDay bool
|
||
MaxPointAgeHours int
|
||
}
|
||
|
||
// SetTrafficQueueLimits 注入当前采集队列配置;未注入时不校验流量采集间隔。
|
||
func (s *ConfigService) SetTrafficQueueLimits(limits func(ctx context.Context) TrafficQueueLimits) {
|
||
s.trafficQueueLimits = limits
|
||
}
|
||
|
||
// validateTrafficInterval 只对启用中的轮询配置校验流量采集间隔:不超过 24h ÷ (N+2)(跨天清空开启)
|
||
// 或最长点龄 ÷ (N+2)(关闭);停用的配置不校验。
|
||
func (s *ConfigService) validateTrafficInterval(ctx context.Context, config *model.PollingConfig) error {
|
||
if s.trafficQueueLimits == nil || config.Status != 1 {
|
||
return nil
|
||
}
|
||
return checkTrafficInterval(config, s.trafficQueueLimits(ctx))
|
||
}
|
||
|
||
func checkTrafficInterval(config *model.PollingConfig, limits TrafficQueueLimits) error {
|
||
limit := cardflow.MaxCollectionInterval(limits.Size, limits.ClearOnNewDay, limits.MaxPointAgeHours, constants.TrafficQueueIntervalSpare)
|
||
if limit <= 0 || config.CarddataCheckInterval == nil || *config.CarddataCheckInterval <= 0 {
|
||
return nil
|
||
}
|
||
interval := time.Duration(*config.CarddataCheckInterval) * time.Second
|
||
if interval <= limit {
|
||
return nil
|
||
}
|
||
return errors.New(errors.CodeInvalidParam, fmt.Sprintf(
|
||
"轮询配置「%s」流量检查间隔 %d 秒超过上限 %d 秒(采集队列长度 %d,留 %d 次冗余),请调小间隔",
|
||
config.ConfigName, *config.CarddataCheckInterval, int64(limit/time.Second), limits.Size, constants.TrafficQueueIntervalSpare))
|
||
}
|
||
|
||
// CheckEnabledTrafficIntervals 校验全部启用中的轮询配置在给定队列配置下是否都满足流量采集间隔上限,
|
||
// 用于修改队列长度、跨天清空、最长点龄前的拦截。
|
||
func CheckEnabledTrafficIntervals(ctx context.Context, db *gorm.DB, limits TrafficQueueLimits) error {
|
||
var configs []*model.PollingConfig
|
||
if err := db.WithContext(ctx).Where("status = ? AND carddata_check_interval > 0", 1).Find(&configs).Error; err != nil {
|
||
return errors.Wrap(errors.CodeDatabaseError, err, "查询启用中的轮询配置失败")
|
||
}
|
||
for _, config := range configs {
|
||
if err := checkTrafficInterval(config, limits); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
return nil
|
||
}
|