Files
junhong_cmp_fiber/pkg/constants/gateway_rate_limit.go
邹进 42e881576d
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m33s
feat: 卡网关按运营商账户限流并记录停复机调用
- 新增网关限流:按本系统运营商账户(卡 carrier_id)→ 限流组 → 操作限制每秒请求数,每次 HTTP 尝试计量,默认限流、仅后台人工点击/通道阈值/自动续费/手动刷新豁免;支持只统计与拦截两种模式,默认只统计
- Asynq 遇限流不计失败、固定短延迟重试;轮询任务与停复机业务重试遇限流短延迟重排
- 停机、复机不再使用网关内部重试,只发一次请求
- 网关返回结构化错误;新增上游错误分类规则表与测试接口
- 新增按月分区的停复机记录表:系统自动停复机只写记录,不再写统一审计与集成日志;普通轮询查询不再写集成日志
- 新增限流组、错误分类、停复机记录、按账户调用统计与枚举后台接口
- 迁移 000243~000246;同步 OpenSpec 提案(含后续 6 个 change)与技术方案、工程约束
2026-10-24 15:06:41 +09:00

244 lines
9.4 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 constants
import (
"fmt"
"time"
)
// 卡网关操作:限流组、错误分类与调用统计共用的操作标识。
const (
// GatewayOpQueryFlow 查流量。
GatewayOpQueryFlow = "query_flow"
// GatewayOpQueryStatus 查卡状态。
GatewayOpQueryStatus = "query_status"
// GatewayOpQueryRealname 查实名。
GatewayOpQueryRealname = "query_realname"
// GatewayOpStop 停机。
GatewayOpStop = "stop"
// GatewayOpStart 复机。
GatewayOpStart = "start"
)
// GatewayCardOperations 是受运营商账户限流约束的卡网关操作全集。
var GatewayCardOperations = []string{GatewayOpQueryFlow, GatewayOpQueryStatus, GatewayOpQueryRealname, GatewayOpStop, GatewayOpStart}
// GatewayOperationName 返回卡网关操作的中文名称。
func GatewayOperationName(op string) string {
switch op {
case GatewayOpQueryFlow:
return "查流量"
case GatewayOpQueryStatus:
return "查状态"
case GatewayOpQueryRealname:
return "查实名"
case GatewayOpStop:
return "停机"
case GatewayOpStart:
return "复机"
default:
return "未知"
}
}
// IsGatewayCardOperation 判断是否为合法的卡网关操作。
func IsGatewayCardOperation(op string) bool {
for _, item := range GatewayCardOperations {
if item == op {
return true
}
}
return false
}
// 网关调用错误类别(结构化错误与分钟计数共用)。
const (
// GatewayErrorNetwork 网络错误(连接失败、DNS 等)。
GatewayErrorNetwork = "network"
// GatewayErrorTimeout 请求超时,结果未知。
GatewayErrorTimeout = "timeout"
// GatewayErrorHTTP HTTP 状态码异常。
GatewayErrorHTTP = "http"
// GatewayErrorInvalidResponse 响应无效。
GatewayErrorInvalidResponse = "invalid_response"
// GatewayErrorUpstream 上游业务错误(再经错误分类细分)。
GatewayErrorUpstream = "upstream"
// GatewayErrorRateLimited 本系统限流拒绝,未发出请求。
GatewayErrorRateLimited = "rate_limited"
// GatewayResultSuccess 调用成功(计数用)。
GatewayResultSuccess = "success"
)
// 上游错误分类类别(tb_gateway_error_classification.category)。
const (
// GatewayClassRateLimitedUpstream 上游频率限制。
GatewayClassRateLimitedUpstream = "rate_limited_upstream"
// GatewayClassTerminal 上游终态不可操作。
GatewayClassTerminal = "terminal"
// GatewayClassAlreadyTarget 上游表示卡已是目标状态。
GatewayClassAlreadyTarget = "already_target"
// GatewayClassTransient 上游临时故障。
GatewayClassTransient = "transient"
// GatewayClassBusiness 上游业务错误(未命中规则的默认类别)。
GatewayClassBusiness = "business"
// GatewayClassAccountConfig 账户配置错误(凭证、接入参数)。
GatewayClassAccountConfig = "account_config"
)
// GatewayErrorClasses 是上游错误分类类别全集。
var GatewayErrorClasses = []string{GatewayClassRateLimitedUpstream, GatewayClassTerminal, GatewayClassAlreadyTarget, GatewayClassTransient, GatewayClassBusiness, GatewayClassAccountConfig}
// GatewayErrorClassName 返回上游错误分类类别中文名称。
func GatewayErrorClassName(class string) string {
switch class {
case GatewayClassRateLimitedUpstream:
return "上游频率限制"
case GatewayClassTerminal:
return "终态不可操作"
case GatewayClassAlreadyTarget:
return "已是目标状态"
case GatewayClassTransient:
return "临时故障"
case GatewayClassBusiness:
return "业务错误"
case GatewayClassAccountConfig:
return "账户配置错误"
default:
return "未知"
}
}
// 错误分类匹配方式。
const (
// GatewayMatchContains 包含关键字。
GatewayMatchContains = "contains"
// GatewayMatchPrefix 以关键字开头。
GatewayMatchPrefix = "prefix"
// GatewayMatchRegex 正则匹配。
GatewayMatchRegex = "regex"
)
// 限流豁免来源:只有这 4 个入口可以绕过运营商账户限流。
const (
// RateLimitExemptManualClick 后台人工点击停复机。
RateLimitExemptManualClick = "manual_click"
// RateLimitExemptChannelThreshold 通道阈值停复机。
RateLimitExemptChannelThreshold = "channel_threshold"
// RateLimitExemptAutoRenewal 自动续费停复机。
RateLimitExemptAutoRenewal = "auto_renewal"
// RateLimitExemptManualRefresh 手动刷新。
RateLimitExemptManualRefresh = "manual_refresh"
)
// 限流模式(polling.rate_limit_mode)。
const (
// RateLimitModeObserve 只统计不拦截。
RateLimitModeObserve = "observe"
// RateLimitModeEnforce 拦截。
RateLimitModeEnforce = "enforce"
)
// 轮询模块受控系统配置。
const (
// SystemConfigModulePolling 是轮询与网关限流配置模块。
SystemConfigModulePolling = "polling"
// SystemConfigPollingRateLimitMode 网关限流模式。
SystemConfigPollingRateLimitMode = "polling.rate_limit_mode"
// SystemConfigPollingGatewayDefaultQPS 默认每秒请求上限。
SystemConfigPollingGatewayDefaultQPS = "polling.gateway_default_qps"
// SystemConfigPollingRateLimitedRetryDelay Asynq 任务遇限流后的固定重试延迟(秒)。
SystemConfigPollingRateLimitedRetryDelay = "polling.rate_limited_retry_delay_seconds"
// SystemConfigPollingRateLimitDeferAlert 限流累计推迟告警阈值(秒)。
SystemConfigPollingRateLimitDeferAlert = "polling.rate_limit_defer_alert_seconds"
// SystemConfigPollingStopResumeRecordRetention 停复机记录保留月数。
SystemConfigPollingStopResumeRecordRetention = "polling.stop_resume_record_retention_months"
// SystemConfigPollingStopResumeRecordPremake 停复机记录提前建分区月数。
SystemConfigPollingStopResumeRecordPremake = "polling.stop_resume_record_premake_months"
)
// TaskTypeStopResumeRecordPartition 停复机记录分区维护定时任务(每日执行,使用数据清理队列)。
const TaskTypeStopResumeRecordPartition = "stop_resume_record:partition"
// 停复机记录动作与结果(tb_card_stop_resume_record)。
const (
// StopResumeActionStop 停机。
StopResumeActionStop = "stop"
// StopResumeActionStart 复机。
StopResumeActionStart = "start"
// StopResumeRecordSuccess 成功。
StopResumeRecordSuccess = "success"
// StopResumeRecordFailed 失败。
StopResumeRecordFailed = "failed"
// StopResumeRecordUnknown 结果未知。
StopResumeRecordUnknown = "unknown"
// StopResumeRecordAlreadyTarget 已是目标状态。
StopResumeRecordAlreadyTarget = "already_target"
// StopResumeRecordSkipped 跳过(未到单卡最小重试间隔)。
StopResumeRecordSkipped = "skipped"
)
const (
// RateLimitGroupStatusDisabled 限流组停用。
RateLimitGroupStatusDisabled = 0
// RateLimitGroupStatusEnabled 限流组启用。
RateLimitGroupStatusEnabled = 1
// GatewayRateLimitWindow 限流滑动窗口长度。
GatewayRateLimitWindow = time.Second
// GatewayRateLimitConfigTTL 限流组与模式在进程内缓存的时长,超过即重新读取,保证后台修改数秒内生效。
GatewayRateLimitConfigTTL = 5 * time.Second
// GatewayCardLastErrorTTL 卡最近一次网关错误保留时长。
GatewayCardLastErrorTTL = 30 * 24 * time.Hour
// GatewayCallStatTTL 分钟计数保留时长(覆盖只统计模式一周的评估需要)。
GatewayCallStatTTL = 8 * 24 * time.Hour
// GatewayCardCarrierCacheTTL ICCID 到运营商账户映射的缓存时长。
GatewayCardCarrierCacheTTL = 10 * time.Minute
// GatewayProviderMessageMaxLen 上游信息落库或展示的最大长度(按字符)。
GatewayProviderMessageMaxLen = 200
// StopResumeRecordQueryMaxDays 停复机记录列表单次查询的最大时间跨度(天)。
StopResumeRecordQueryMaxDays = 31
)
// RedisGatewayQPSKey 返回账户限流组的滑动窗口 Key;carrierID 为 0 表示无法解析账户的卡(单独计量)。
func RedisGatewayQPSKey(carrierID uint, groupCode string) string {
return fmt.Sprintf("gateway:qps:%d:%s", carrierID, groupCode)
}
// RedisGatewayGlobalQPSKey 返回全局限流组的滑动窗口 Key。
func RedisGatewayGlobalQPSKey(groupCode string) string {
return fmt.Sprintf("gateway:qps:global:%s", groupCode)
}
// RedisGatewayQPSHighWaitingKey 返回限流组正在等待名额的高优先级请求数 Key。
func RedisGatewayQPSHighWaitingKey(carrierID uint, groupCode string) string {
return RedisGatewayQPSKey(carrierID, groupCode) + ":high_waiting"
}
// RedisGatewayCallStatKey 返回网关调用分钟计数 Key(Hash:结果类别 → 次数、耗时分桶)。
func RedisGatewayCallStatKey(carrierID uint, op, minute string) string {
return fmt.Sprintf("gateway:stat:%d:%s:%s", carrierID, op, minute)
}
// RedisGatewayCardCarrierKey 返回 ICCID 到运营商账户 ID 映射的缓存 Key。
func RedisGatewayCardCarrierKey(iccid string) string {
return fmt.Sprintf("gateway:card_carrier:%s", iccid)
}
// RedisGatewayRateLimitGroupsKey 返回限流组配置缓存 Key。
func RedisGatewayRateLimitGroupsKey() string {
return "gateway:rate_limit_groups"
}
// RedisGatewayErrorClassificationKey 返回错误分类规则缓存 Key。
func RedisGatewayErrorClassificationKey() string {
return "gateway:error_classification"
}
// RedisRateLimitDeferStartKey 返回任务首次被限流时间的 Key,用于累计推迟告警。
func RedisRateLimitDeferStartKey(taskKey string) string {
return fmt.Sprintf("gateway:rate_limit_defer:%s", taskKey)
}
// RedisGatewayCardLastErrorKey 返回卡某网关操作最近一次错误的 Key(Hash:类别、码、信息、时间)。
func RedisGatewayCardLastErrorKey(iccid, op string) string {
return fmt.Sprintf("gateway:last_error:%s:%s", iccid, op)
}