Files
sub2api/backend/internal/service/openai_profit_control.go
T
李建琦 6d655c9903
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
Sub2API v1.0 - AI API 网关(二开初始版本,基于上游 Wei-Shaw/sub2api)
2026-08-21 18:30:13 +08:00

458 lines
23 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 service
// 分组利润控制(配套 migration 192/193 的 groups.profit_* 字段)。
//
// 定位:利润控制是"候选准入过滤",只决定账号能否进入调度候选池;既有的排序、
// 评分、粘性、熔断、负载均衡在合格账号之间照常工作,本文件不改变它们的行为。
//
// 准入条件:
//
// U(尝试时刻) <= D(pricingAt) × (1 profit_min_margin profit_safety_buffer)
//
// - D(用户售价倍率)固定在请求开始的 pricingAt:同一请求的全部 failover 与
// 最终扣费共用同一 D(RecordUsage 的高峰因子同样取 pricingAt),一个请求
// 不会中途变价。D 与计费完全同源:按请求真实计费分组(ctxkey.Group,即
// apiKey 自身分组;composite 请求为父分组)做 ResolveUserGroupRateMultiplier
// (用户-分组覆盖 ?? 分组默认)× Group.PeakMultiplierAt(pricingAt),绝不在
// 用户有覆盖时退回分组默认;开关与 margin/buffer 则始终取被调度
// openai/grok 分组。
// - U(上游成本倍率)取 accounts.rate_multiplier。倍率可以由运营者手工维护,
// 也可以由上游倍率探测同步写回;利润门不再耦合探测协议、新鲜度或账号类型。
// 0 是合法的免费上游倍率;nil、负数、NaN、Inf 属于非法数据并保守拒绝。
//
// 装门点(gate 随 ctx 传播,请求内复用,覆盖等待/重试/failover/抢槽后终检):
// - handler 各文本入口经 WithOpenAIRequestPricingContext 在请求开始统一装门并
// 固定 pricingAt。生图意图只用于能力路由与图片计费,不决定是否装门:混合
// /v1/responses 请求(含声明了生图工具的请求)的 token 计费部分仍受利润门
// 保护,请求体内的任何工具声明都不能作为关门开关。
// - 门范围之外的路径显式携带 WithOpenAIProfitControlSuppressed 标记:独立
// 图片/视频端点与 Grok 媒体(媒体计费另有倍率来源)、count_tokens(不计费)、
// live(按时长计费)。所有装门点(含防御性装门)都尊重该标记。
// - selectAccountWithScheduler 顶部:唯一文本调度入口的防御性装门(ctx 已有
// 同分组门则复用,保证 failover 阈值稳定);requiredImageCapability != ""
// 的专用图片调度不装门。
// - 公开 SelectAccountWithLoadAwareness / SelectAccountByPreviousResponseID
// 防御性装门,保证不经唯一入口的调用方无法绕过。
// - 选号结果通过 AccountSelectionResult 携带真实生效的门(composite/fallback
// 路由可能解析出与入口分组不同的门),handler 经
// ContextWithSelectionProfitGate 重放后再做抢槽后终检与准入后粘性绑定。
// - 长连接(Responses WS)在每个 turn 开始经 WithOpenAITurnPricingContext
// 重新冻结 pricingAt 并重装门:turn 的准入与计费同源,跨峰谷边界不再共用
// 建连时刻的 D。
//
// 否决点(消费 gate,任何 fallback 都无法把已排除账号重新放回):
// - defaultOpenAIAccountScheduler.isAccountRequestCompatibleReason:候选池
// 过滤 + 调度器内抢槽后终检共用,named reason 进入 openAISelectionFilterStats。
// - isOpenAICompatibleAccountEligibleForRequestlegacy 引擎与 DB recheck 共用。
// - resolveAccountByPreviousResponseIDForCapabilityprevious_response 粘连
// 两阶段校验;与 quota auto-pause 同语义,跳过复用但不删除绑定。
// - handler 槽位获取后终检(OpenAIProfitControlVeto):快速抢槽与 WaitPlan
// 排队成功后复核,越线则释放槽位、加入本请求排除集重新选号,全池耗尽才
// 返回标准 no available accounts。
//
// 失败语义:分组配置读取失败时放行并告警(fail-open)。这是"配置系统故障时
// 可用性优先"的显式取舍——该异常窗口内利润保证不成立,靠 WARN 与采样观测
// 暴露,绝不把瞬时 DB 抖动放大成全站不可调度。
//
// 可观测性:按分组和平台累计装门/threshold 否决/invalid-rate 否决/终检刷新
// 失败计数,≥5 分钟采样输出一条 Infoprofit_control_activity),无逐请求日志。
import (
"context"
"errors"
"fmt"
"log/slog"
"math"
"sync"
"sync/atomic"
"time"
"github.com/Wei-Shaw/sub2api/internal/pkg/ctxkey"
"github.com/Wei-Shaw/sub2api/internal/pkg/timezone"
)
const (
// profitControlRateEpsilon 吸收 decimal(10,4) 落库与浮点乘法的边界误差:
// U 与阈值的相对差在该量级内视为相等(即 U == 阈值 判定为合格)。
profitControlRateEpsilon = 1e-9
// 进入 openAISelectionFilterStats 的排除原因,全排除时出现在
// "no available accounts" 的内部统计摘要里(与 quota_auto_pause 等同通道)。
openAIProfitFilterReasonThreshold = "profit_threshold"
openAIProfitFilterReasonInvalidAccountRate = "profit_invalid_account_rate"
// profitControlActivityLogInterval 是按分组采样输出累计计数的最小间隔。
profitControlActivityLogInterval = 5 * time.Minute
)
type openAIProfitControlGateCtxKey struct{}
// openAIProfitControlSuppressCtxKey 标记本请求显式跳过利润门(独立图片/视频
// 端点、Grok 媒体、count_tokens、live 等利润门范围外流量)。所有装门点看到该
// 标记后一律不装门,防止 service 层防御性装门把边界外流量重新拉回利润过滤。
type openAIProfitControlSuppressCtxKey struct{}
// openAIPricingAtCtxKey 携带请求级定价时刻 pricingAt:门的 D 与 RecordUsage
// 的高峰因子共用,保证一个请求从准入到扣费不中途变价。
type openAIPricingAtCtxKey struct{}
// clampProfitControlThreshold 归一化利润门阈值。Validate/Normalize 已保证
// margin+buffer < 1,这里只对存量脏数据兜底:阈值非有限或为负时按 0 处理
// (等价于只放行免费上游)。装门点与 profit-preview 共用,避免口径漂移。
func clampProfitControlThreshold(threshold float64) float64 {
if math.IsNaN(threshold) || math.IsInf(threshold, 0) || threshold < 0 {
return 0
}
return threshold
}
// profitControlOverThreshold 是"上游倍率越线"的唯一定义:相对 epsilon 吸收
// decimal(10,4) 落库与浮点乘法的边界误差,U == 阈值 判定为合格。
// 线上否决点与 profit-preview 共用,两者不得各自实现。
func profitControlOverThreshold(upstream, threshold float64) bool {
return upstream-threshold > profitControlRateEpsilon*math.Max(1, math.Abs(threshold))
}
// openAIProfitControlGate 是一个请求的利润准入门。除 pricingAt 外全部为预计算
// 标量:候选过滤热路径上每账号只做一次快照解码与一次浮点比较。
type openAIProfitControlGate struct {
// groupID 是门配置来源的被调度分组;请求内按分组复用(failover 阈值稳定),
// composite 等跨分组调度切换分组时重新解析。
groupID int64
// platform 是利润配置所在分组的平台,用于按平台观测门是否真实生效。
platform string
// threshold = D(pricingAt) × (1 margin buffer),账号倍率必须 <= 它。
threshold float64
// pricingAt 是本请求的统一定价时刻(D 侧)。
pricingAt time.Time
}
// WithOpenAIRequestPricingContext 在请求开始处装配请求级定价上下文:固定
// pricingAt(返回给调用方,供 RecordUsage 入参共用同一时刻),并按分组安装
// 利润门。ctx 携带 WithOpenAIProfitControlSuppressed 标记(门范围外流量)时
// 只固定 pricingAt、不装门。handler 各文本入口应在选号循环前调用一次。
func (s *OpenAIGatewayService) WithOpenAIRequestPricingContext(ctx context.Context, groupID *int64) (context.Context, time.Time) {
pricingAt := timezone.Now()
ctx = context.WithValue(ctx, openAIPricingAtCtxKey{}, pricingAt)
return s.withOpenAIProfitControlGate(ctx, groupID), pricingAt
}
// WithOpenAIProfitControlSuppressed 标记本请求在利润门范围之外(独立图片/视频
// 端点、Grok 媒体、count_tokens、live)。所有装门点(含 service 层防御性装门)
// 都尊重该标记;它只关闭利润准入过滤,不影响定价上下文与计费。
func WithOpenAIProfitControlSuppressed(ctx context.Context) context.Context {
return context.WithValue(ctx, openAIProfitControlSuppressCtxKey{}, struct{}{})
}
// WithOpenAITurnPricingContext 在长连接(Responses WS)的每个 turn 开始重新
// 冻结 pricingAt 并按当前配置重装利润门,使 turn 的准入与计费同源:峰前建连
// 保活不再让后续 turn 继续按建连时刻的谷价定价。连接可能被调度到与入口分组
// 不同的分组(composite 成员分组),turn 级重装以连接上已装门的调度分组为准;
// 连接从未装门时才回退入口分组。抑制标记下只刷新 pricingAt。
func (s *OpenAIGatewayService) WithOpenAITurnPricingContext(ctx context.Context, groupID *int64) (context.Context, time.Time) {
pricingAt := timezone.Now()
ctx = context.WithValue(ctx, openAIPricingAtCtxKey{}, pricingAt)
if _, suppressed := ctx.Value(openAIProfitControlSuppressCtxKey{}).(struct{}); suppressed {
return ctx, pricingAt
}
if existing, ok := ctx.Value(openAIProfitControlGateCtxKey{}).(*openAIProfitControlGate); ok && existing != nil {
gid := existing.groupID
groupID = &gid
}
gate := s.resolveOpenAIProfitControlGate(ctx, groupID)
if gate == nil {
// 分组已关门(或配置读取失败 fail-open):清除旧 turn 的门,后续 turn
// 按无门放行,与 HTTP 路径的开关语义一致。
if existing, ok := ctx.Value(openAIProfitControlGateCtxKey{}).(*openAIProfitControlGate); ok && existing != nil {
return context.WithValue(ctx, openAIProfitControlGateCtxKey{}, (*openAIProfitControlGate)(nil)), pricingAt
}
return ctx, pricingAt
}
openAIProfitControlObserverInstance.recordInstall(gate.groupID, gate.platform, gate.threshold)
return context.WithValue(ctx, openAIProfitControlGateCtxKey{}, gate), pricingAt
}
// openAIPricingAtFromContext 返回请求级定价时刻;未装配(内部调用、非文本
// 入口)时 ok=false,调用方回退 timezone.Now() 保持既有行为。
func openAIPricingAtFromContext(ctx context.Context) (time.Time, bool) {
pricingAt, ok := ctx.Value(openAIPricingAtCtxKey{}).(time.Time)
return pricingAt, ok && !pricingAt.IsZero()
}
// OpenAIPricingAtFromContext 是 handler 侧读取请求级定价时刻的公开入口(未装配
// 时为零值,RecordUsage 对零值回退记录时刻)。供跨函数传递 pricingAt 不便的
// 记录路径直接从请求 ctx 取值。
func OpenAIPricingAtFromContext(ctx context.Context) time.Time {
pricingAt, _ := openAIPricingAtFromContext(ctx)
return pricingAt
}
// withOpenAIProfitControlGate 解析分组利润控制配置;启用时把预计算好的准入门
// 装进 ctx。抑制标记、未启用/非 openai 分组/无法取到分组配置时原样返回 ctx
// (门不存在,全部否决点自动放行,既有行为零变化)。ctx 已有同分组门时直接
// 复用:同一请求的全部 failover 重入共享同一阈值。
func (s *OpenAIGatewayService) withOpenAIProfitControlGate(ctx context.Context, groupID *int64) context.Context {
if _, suppressed := ctx.Value(openAIProfitControlSuppressCtxKey{}).(struct{}); suppressed {
return ctx
}
if groupID != nil {
if existing, ok := ctx.Value(openAIProfitControlGateCtxKey{}).(*openAIProfitControlGate); ok && existing != nil && existing.groupID == *groupID {
return ctx
}
}
gate := s.resolveOpenAIProfitControlGate(ctx, groupID)
if gate == nil {
// 被调度分组无门(未启用/非 openai/配置读取失败)而 ctx 带着其他分组的
// 请求门时清除之:门配置取被调度分组,父分组阈值不得泄漏到成员分组
//composite/模型路由等跨分组调度)。typed-nil 覆盖值由否决点按无门放行。
if existing, ok := ctx.Value(openAIProfitControlGateCtxKey{}).(*openAIProfitControlGate); ok && existing != nil && groupID != nil && existing.groupID != *groupID {
return context.WithValue(ctx, openAIProfitControlGateCtxKey{}, (*openAIProfitControlGate)(nil))
}
return ctx
}
openAIProfitControlObserverInstance.recordInstall(gate.groupID, gate.platform, gate.threshold)
return context.WithValue(ctx, openAIProfitControlGateCtxKey{}, gate)
}
func (s *OpenAIGatewayService) resolveOpenAIProfitControlGate(ctx context.Context, groupID *int64) *openAIProfitControlGate {
if s == nil || groupID == nil || *groupID <= 0 {
return nil
}
// 门配置取被调度分组。直连请求(ctx 认证分组即调度分组,生产绝大多数流量)
// 直接复用 auth cache 分组,热路径零额外查询;composite 父分组路由到成员
// 分组等 ID 不一致场景才回源仓库读取。auth 快照的分组字段完备性由
// GetByKeyForAuth 投影 + 集成测试保证(防投影漏列导致门静默失效)。
var group *Group
if ctxGroup, ok := ctx.Value(ctxkey.Group).(*Group); ok && IsGroupContextValid(ctxGroup) && ctxGroup.ID == *groupID {
group = ctxGroup
} else if s.schedulerSnapshot != nil {
// Lite 读取:门只用平台/倍率/利润/高峰字段,不需要账号计数聚合。
loaded, err := s.schedulerSnapshot.GetGroupByIDLite(ctx, *groupID)
if err != nil {
// fail-open:配置系统故障时可用性优先,该窗口内利润保证不成立,
// 依赖 WARN 暴露;不把瞬时 DB 抖动放大成全站不可调度。
slog.Warn("profit_control_group_load_failed", "group_id", *groupID, "error", err)
return nil
}
group = loaded
}
if group == nil || !group.ProfitControlEnabled ||
(group.Platform != PlatformOpenAI && group.Platform != PlatformGrok) {
return nil
}
pricingAt, ok := openAIPricingAtFromContext(ctx)
if !ok {
pricingAt = timezone.Now()
}
// D 与计费完全同源(RecordUsage 组合):计费永远按 apiKey 自身分组
//composite 请求即父分组)的"用户覆盖 ?? 分组默认 × 高峰因子"计算,
// 因此优先取认证中间件放入 ctx 的分组;ctx 中无有效分组(内部调用)时
// 退回调度分组组合,直连 openai 分组场景两者等价。
billingGroup := group
if ctxGroup, ok := ctx.Value(ctxkey.Group).(*Group); ok && IsGroupContextValid(ctxGroup) {
billingGroup = ctxGroup
}
downstream := billingGroup.RateMultiplier
if userID, _ := ctx.Value(ctxkey.UserID).(int64); userID > 0 {
downstream = s.ResolveUserGroupRateMultiplier(ctx, userID, billingGroup.ID, billingGroup.RateMultiplier)
}
downstream *= billingGroup.PeakMultiplierAt(pricingAt)
deduction := group.ProfitMinMargin + group.ProfitSafetyBuffer
threshold := clampProfitControlThreshold(downstream * (1 - deduction))
return &openAIProfitControlGate{
groupID: *groupID,
platform: group.Platform,
threshold: threshold,
pricingAt: pricingAt,
}
}
// attachSelectionProfitGate 把调度上下文里生效的利润门记录到选号结果上。门在
// 选号函数内部的局部 ctx 上安装(composite/fallback 路由还可能解析出与入口
// 分组不同的门),不随返回值离开调度栈;结果携带后 handler 才能对"真实过滤了
// 候选的那个门"做抢槽后终检与准入后绑定。
func attachSelectionProfitGate(ctx context.Context, sel *AccountSelectionResult) *AccountSelectionResult {
if sel == nil {
return nil
}
if gate, ok := ctx.Value(openAIProfitControlGateCtxKey{}).(*openAIProfitControlGate); ok && gate != nil {
sel.profitGate = gate
}
return sel
}
// ContextWithSelectionProfitGate 把选号时真实生效的利润门重放到 ctx 上。
// handler 在拿到选号结果后必须用返回的 ctx 做抢槽后终检
// ProfitControlVetoLatest / GatewayProfitControlVetoLatest)与准入后粘性
// 绑定,否则这两步会因为看不到调度栈内安装的门而退化为空操作。
func ContextWithSelectionProfitGate(ctx context.Context, sel *AccountSelectionResult) context.Context {
if sel == nil || sel.profitGate == nil {
return ctx
}
if existing, ok := ctx.Value(openAIProfitControlGateCtxKey{}).(*openAIProfitControlGate); ok && existing == sel.profitGate {
return ctx
}
return context.WithValue(ctx, openAIProfitControlGateCtxKey{}, sel.profitGate)
}
// openAIProfitControlVetoReason 报告利润门是否否决该账号。ctx 中没有门
// (分组未启用利润控制或本请求跳门)或账号为 nil 时一律放行。
func openAIProfitControlVetoReason(ctx context.Context, account *Account) (bool, string) {
gate, _ := ctx.Value(openAIProfitControlGateCtxKey{}).(*openAIProfitControlGate)
if gate == nil || account == nil {
return false, ""
}
if account.RateMultiplier == nil ||
math.IsNaN(*account.RateMultiplier) ||
math.IsInf(*account.RateMultiplier, 0) ||
*account.RateMultiplier < 0 {
openAIProfitControlObserverInstance.recordVeto(gate.groupID, gate.platform, gate.threshold, openAIProfitFilterReasonInvalidAccountRate)
return true, openAIProfitFilterReasonInvalidAccountRate
}
upstream := *account.RateMultiplier
if profitControlOverThreshold(upstream, gate.threshold) {
openAIProfitControlObserverInstance.recordVeto(gate.groupID, gate.platform, gate.threshold, openAIProfitFilterReasonThreshold)
return true, openAIProfitFilterReasonThreshold
}
return false, ""
}
// OpenAIProfitControlVeto 是 handler 层槽位获取后终检的公开入口:语义与调度
// 内否决点完全一致。ctx 必须是经 WithOpenAIRequestPricingContext 装配过的
// 请求上下文,否则视为无门放行。
func OpenAIProfitControlVeto(ctx context.Context, account *Account) (bool, string) {
return openAIProfitControlVetoReason(ctx, account)
}
// ProfitControlVetoLatest performs the handler-side terminal check after a
// concurrency slot is actually acquired. The latest cached account replaces
// the selection snapshot when available, so a probe/manual rate change during
// wait time cannot pass on a stale pointer.
func (s *OpenAIGatewayService) ProfitControlVetoLatest(ctx context.Context, selected *Account) (*Account, bool, string) {
if s == nil {
return selected, false, ""
}
return profitControlVetoLatest(ctx, selected, s.schedulerSnapshot)
}
// bindOpenAIStickySessionDuringSelection preserves the official eager binding
// behavior for requests without a profit gate. Profit-controlled requests bind
// only after the terminal post-slot check, so an account rejected after a rate
// refresh cannot become the new sticky target.
func (s *OpenAIGatewayService) bindOpenAIStickySessionDuringSelection(ctx context.Context, groupID *int64, sessionHash string, accountID int64) error {
if gatewayProfitControlGateActive(ctx) {
return nil
}
return s.BindStickySession(ctx, groupID, sessionHash, accountID)
}
// BindStickySessionAfterProfitAdmission records the terminally admitted
// account. Without a profit gate it preserves the pre-existing eager binding
// behavior at the handler bind points. With a gate it never overwrites a
// different binding that already exists, so a temporarily ineligible account
// remains sticky and becomes eligible again automatically after its rate
// recovers.
func (s *OpenAIGatewayService) BindStickySessionAfterProfitAdmission(ctx context.Context, groupID *int64, sessionHash string, accountID int64) error {
if sessionHash == "" || accountID <= 0 {
return nil
}
if !gatewayProfitControlGateActive(ctx) {
return s.BindStickySession(ctx, groupID, sessionHash, accountID)
}
existingAccountID, err := s.getStickySessionAccountID(ctx, groupID, sessionHash)
if err != nil && !errors.Is(err, ErrStickySessionNotFound) {
slog.Warn("profit_control_sticky_binding_read_failed", "group_id", derefGroupID(groupID), "account_id", accountID, "error", err)
return nil
}
if existingAccountID > 0 && existingAccountID != accountID {
return nil
}
return s.BindStickySession(ctx, groupID, sessionHash, accountID)
}
// ---- 可观测性:按分组累计计数 + 采样日志(无逐请求输出) ----
//
// 计数按"每次准入评估"累计,而非每请求:粘性层校验与候选池过滤可能对同一账号
// 各评估一次,failover 重入也会再次计数。计数用于确认门在真实流量上生效及否决
// 构成,不能当作精确的请求数或账号数。
type openAIProfitControlGroupStats struct {
installs atomic.Int64
vetoThreshold atomic.Int64
vetoInvalidRate atomic.Int64
refreshFailures atomic.Int64
lastLogUnixMilli atomic.Int64
}
type openAIProfitControlObserver struct {
groups sync.Map // "platform:groupID" -> *openAIProfitControlGroupStats
}
var openAIProfitControlObserverInstance = &openAIProfitControlObserver{}
func profitControlObserverKey(groupID int64, platform string) string {
return platform + ":" + fmt.Sprintf("%d", groupID)
}
func (o *openAIProfitControlObserver) stats(groupID int64, platform string) *openAIProfitControlGroupStats {
key := profitControlObserverKey(groupID, platform)
if v, ok := o.groups.Load(key); ok {
if s, ok := v.(*openAIProfitControlGroupStats); ok {
return s
}
}
v, _ := o.groups.LoadOrStore(key, &openAIProfitControlGroupStats{})
if s, ok := v.(*openAIProfitControlGroupStats); ok {
return s
}
// 不可达:map 中只存 *openAIProfitControlGroupStats;兜底返回独立实例避免 panic。
return &openAIProfitControlGroupStats{}
}
func (o *openAIProfitControlObserver) recordInstall(groupID int64, platform string, threshold float64) {
s := o.stats(groupID, platform)
s.installs.Add(1)
o.maybeLog(groupID, platform, threshold, s)
}
func (o *openAIProfitControlObserver) recordVeto(groupID int64, platform string, threshold float64, reason string) {
s := o.stats(groupID, platform)
switch reason {
case openAIProfitFilterReasonThreshold:
s.vetoThreshold.Add(1)
case openAIProfitFilterReasonInvalidAccountRate:
s.vetoInvalidRate.Add(1)
}
o.maybeLog(groupID, platform, threshold, s)
}
func (o *openAIProfitControlObserver) recordRefreshFailure(groupID int64, platform string, threshold float64) {
s := o.stats(groupID, platform)
s.refreshFailures.Add(1)
o.maybeLog(groupID, platform, threshold, s)
}
// maybeLog 以 CAS 保证同分组 ≥ profitControlActivityLogInterval 才输出一条
// 累计计数 Info;计数为进程内累计值,用于确认门在真实流量上生效及否决构成。
func (o *openAIProfitControlObserver) maybeLog(groupID int64, platform string, threshold float64, s *openAIProfitControlGroupStats) {
now := time.Now().UnixMilli()
last := s.lastLogUnixMilli.Load()
if last != 0 && now-last < profitControlActivityLogInterval.Milliseconds() {
return
}
if !s.lastLogUnixMilli.CompareAndSwap(last, now) {
return
}
slog.Info("profit_control_activity",
"group_id", groupID,
"platform", platform,
"threshold", threshold,
"installs_total", s.installs.Load(),
"veto_threshold_total", s.vetoThreshold.Load(),
"veto_invalid_account_rate_total", s.vetoInvalidRate.Load(),
"refresh_failure_total", s.refreshFailures.Load(),
)
}