Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
自动停复机统一经停复机指令队列执行(全局开关 polling.stop_resume.queue_enabled,默认关闭): - 统一判断函数 decideCard,新旧路径共用;暂停轮询的卡在套餐到期、退款场景照常停机 - 同卡一条指令、版本号覆盖;领取校验单卡最小重试间隔;先于卡任务领取,不受 scheduler_mode 限制 - 执行器只调用一次网关,按错误分类退避与告警,结果未知在队列内确认 - 设备维度判断合并请求与场景,版本变化再判断,旧路径持设备锁时推后 - 套餐激活、重置、订单、流量扣减、套餐到期、退款、实名管控修改改为请求评估 - 监控增加停复机队列与近 1 小时执行计数,单卡轮询状态返回当前指令 - 迁移 000255 插入开关与告警、退避参数 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
175 lines
7.0 KiB
Go
175 lines
7.0 KiB
Go
package constants
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
)
|
||
|
||
// 停复机指令队列(add-stop-resume-command-queue)。
|
||
|
||
// 停复机请求评估场景:随请求评估与指令保存,执行前重新判断沿用同一场景。
|
||
const (
|
||
StopResumeScenePolling = "polling" // 套餐步骤(周期评估)
|
||
StopResumeSceneFlowObserved = "flow_observed" // 流量增加观测
|
||
StopResumeSceneNetworkObserved = "network_observed" // 网络状态变化观测
|
||
StopResumeSceneRealnameObserved = "realname_observed" // 实名变化观测(含人工实名)
|
||
StopResumeSceneActivation = "activation" // 套餐激活
|
||
StopResumeSceneReset = "reset" // 流量重置
|
||
StopResumeSceneOrder = "order" // 订单支付后套餐生效
|
||
StopResumeSceneRefund = "refund" // 退款后资产无可用主套餐
|
||
StopResumeScenePackageExpired = "package_expired" // 套餐到期且无其他有效主套餐
|
||
StopResumeSceneRealnameControl = "realname_control" // 运营商账户实名管控修改
|
||
StopResumeSceneUsage = "usage" // 流量扣减后
|
||
)
|
||
|
||
// StopResumeSceneAllowsSuspendedStop 判断场景集合中是否含套餐失效类场景:暂停轮询的卡在这些场景下照常停机。
|
||
func StopResumeSceneAllowsSuspendedStop(scenes []string) bool {
|
||
for _, scene := range scenes {
|
||
if scene == StopResumeScenePackageExpired || scene == StopResumeSceneRefund {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// JoinStopResumeScenes 把场景集合编码为逗号分隔串(去重、去空)。
|
||
func JoinStopResumeScenes(scenes []string) string {
|
||
seen := map[string]bool{}
|
||
parts := make([]string, 0, len(scenes))
|
||
for _, scene := range scenes {
|
||
scene = strings.TrimSpace(scene)
|
||
if scene == "" || seen[scene] {
|
||
continue
|
||
}
|
||
seen[scene] = true
|
||
parts = append(parts, scene)
|
||
}
|
||
return strings.Join(parts, ",")
|
||
}
|
||
|
||
// SplitStopResumeScenes 解析逗号分隔的场景串。
|
||
func SplitStopResumeScenes(raw string) []string {
|
||
if strings.TrimSpace(raw) == "" {
|
||
return nil
|
||
}
|
||
parts := strings.Split(raw, ",")
|
||
scenes := make([]string, 0, len(parts))
|
||
for _, part := range parts {
|
||
if part = strings.TrimSpace(part); part != "" {
|
||
scenes = append(scenes, part)
|
||
}
|
||
}
|
||
return scenes
|
||
}
|
||
|
||
// CheckTypeStopResume 是失败告警表中停复机方向的检查类型。
|
||
const CheckTypeStopResume = "stop_resume"
|
||
|
||
// 停复机指令失败类别(不来自上游错误分类的部分)。
|
||
const (
|
||
StopResumeFailureUnknown = "unknown" // 结果未知(超时、连接失败、可能已受理)
|
||
)
|
||
|
||
// 停复机指令默认参数(账户未配置时使用)。
|
||
const (
|
||
DefaultStopResumeMinIntervalSeconds = 600 // 单卡最小重试间隔:上游卡状态变更每十分钟只允许调用一次
|
||
DefaultStopResumeConfirmDelaySeconds = 60 // 结果未知后的确认延迟
|
||
DefaultStopResumeInflightLimit = 10 // 账户停复机执行上限
|
||
DefaultStopResumeMaxInFlight = 10 // 每进程停复机消费者 max_in_flight
|
||
)
|
||
|
||
// 停复机指令队列受控系统配置键(module = polling)。
|
||
const (
|
||
SystemConfigStopResumeQueueEnabled = "polling.stop_resume.queue_enabled"
|
||
SystemConfigStopResumeUnknownAlert = "polling.stop_resume.unknown_alert_threshold"
|
||
SystemConfigStopResumeBackoff = "polling.stop_resume.backoff_seconds"
|
||
SystemConfigStopResumeAlertFailCount = "polling.stop_resume.alert_fail_count"
|
||
)
|
||
|
||
// ========================================
|
||
// 停复机指令队列 Redis Key
|
||
// ========================================
|
||
|
||
// RedisCarrierStopResumeQueueKey 账户停复机指令队列(ZSET,member=card_id,score=可执行时间毫秒)。
|
||
func RedisCarrierStopResumeQueueKey(carrierID uint) string {
|
||
return fmt.Sprintf("polling:carrier:%d:stop_resume", carrierID)
|
||
}
|
||
|
||
// RedisCarrierStopResumeRunningKey 账户停复机执行中计数(ZSET,member=token,score=租约到期毫秒)。
|
||
func RedisCarrierStopResumeRunningKey(carrierID uint) string {
|
||
return fmt.Sprintf("polling:carrier:%d:sr_running", carrierID)
|
||
}
|
||
|
||
// RedisCardStopResumeCmdKey 卡停复机指令(Hash:action、reason、scenes、source、carrier、ver、fail、ffail、err、pending、unknown、at)。
|
||
func RedisCardStopResumeCmdKey(cardID uint) string {
|
||
return fmt.Sprintf("polling:card:%d:stop_resume_cmd", cardID)
|
||
}
|
||
|
||
// RedisCardStopResumeClaimKey 停复机指令处理中标记,值=派发 token,TTL=租约。
|
||
func RedisCardStopResumeClaimKey(cardID uint) string {
|
||
return fmt.Sprintf("polling:card:%d:sr_claim", cardID)
|
||
}
|
||
|
||
// RedisCardStopResumeExecKey 停复机指令执行权,值=token + 实例。
|
||
func RedisCardStopResumeExecKey(cardID uint) string {
|
||
return fmt.Sprintf("polling:card:%d:sr_exec", cardID)
|
||
}
|
||
|
||
// RedisCardStopResumeLastCallKey 本卡最近一次停复机网关调用时间(毫秒,停机与复机合计)。
|
||
func RedisCardStopResumeLastCallKey(cardID uint) string {
|
||
return fmt.Sprintf("polling:card:%d:sr_last_call", cardID)
|
||
}
|
||
|
||
// RedisDeviceEvalQueueKey 设备判断队列(ZSET,member=device_id,score=可执行时间毫秒)。
|
||
const RedisDeviceEvalQueueKey = "polling:device_eval:queue"
|
||
|
||
// RedisDeviceEvalRunningKey 设备判断执行中计数(ZSET,member=token)。
|
||
const RedisDeviceEvalRunningKey = "polling:device_eval:running"
|
||
|
||
// RedisDeviceEvalDispatchLockKey 设备判断分发锁。
|
||
const RedisDeviceEvalDispatchLockKey = "polling:device_eval:dispatch_lock"
|
||
|
||
// RedisDeviceEvalVersionKey 设备判断版本号(每次请求 INCR)。
|
||
func RedisDeviceEvalVersionKey(deviceID uint) string {
|
||
return fmt.Sprintf("polling:device:%d:eval_ver", deviceID)
|
||
}
|
||
|
||
// RedisDeviceEvalScenesKey 设备待判断场景集合(Set)。
|
||
func RedisDeviceEvalScenesKey(deviceID uint) string {
|
||
return fmt.Sprintf("polling:device:%d:eval_scenes", deviceID)
|
||
}
|
||
|
||
// RedisDeviceEvalClaimKey 设备判断处理中标记,值=token。
|
||
func RedisDeviceEvalClaimKey(deviceID uint) string {
|
||
return fmt.Sprintf("polling:device:%d:eval_claim", deviceID)
|
||
}
|
||
|
||
// RedisDeviceEvalLockKey 设备判断锁(执行权),同一设备同一时刻只有一个判断在执行。
|
||
func RedisDeviceEvalLockKey(deviceID uint) string {
|
||
return fmt.Sprintf("polling:device:%d:eval_lock", deviceID)
|
||
}
|
||
|
||
// NSQStopResumeTopic 返回账户停复机指令 topic。
|
||
func NSQStopResumeTopic(carrierID uint) string {
|
||
return fmt.Sprintf("polling.stop_resume.%d", carrierID)
|
||
}
|
||
|
||
// NSQDeviceEvalTopic 设备判断 topic。
|
||
const NSQDeviceEvalTopic = "polling.device_eval"
|
||
|
||
// 停复机指令执行计数字段(按 10 分钟分桶,供监控汇总近 1 小时)。
|
||
const (
|
||
StopResumeStatSuccess = "success"
|
||
StopResumeStatFailed = "failed"
|
||
StopResumeStatRetry = "retry"
|
||
StopResumeStatUnknown = "unknown"
|
||
)
|
||
|
||
// StopResumeStatBucketSeconds 是停复机执行计数的分桶时长。
|
||
const StopResumeStatBucketSeconds = 600
|
||
|
||
// RedisCarrierStopResumeStatKey 账户停复机执行计数(Hash,field=计数字段),bucket = unix 秒 / 分桶时长。
|
||
func RedisCarrierStopResumeStatKey(carrierID uint, bucket int64) string {
|
||
return fmt.Sprintf("polling:carrier:%d:sr_stats:%d", carrierID, bucket)
|
||
}
|