// quota.go:配额预扣/结算/释放(design-arch §2.3:预扣防超卖,耗尽 402)。 // 预扣在 gateway 认证后、入队前执行;任务终态由 scheduler 回调结算或释放。 package auth import ( "fmt" "time" "onesvm.com/onesvm/browser-server/internal/contract" "onesvm.com/onesvm/browser-server/internal/store" ) // ReserveDaily 预扣当日额度(事务内条件 UPDATE,防超卖)。 // 返回剩余额度;不足时返回 quota 错误(402,不重试)。 func (v *Verifier) ReserveDaily(keyID int64, dailyLimit int, now time.Time) (int, *Error) { if dailyLimit <= 0 { return 0, &Error{Code: contract.CodeQuota, Message: "日配额为 0(未开放)"} } remaining, err := v.db.QuotaReserve(keyID, dailyLimit, now) if err == store.ErrNotFound { return 0, &Error{Code: contract.CodeQuota, Message: "日配额耗尽(402,不重试)"} } if err != nil { return 0, &Error{Code: contract.CodeUpstream, Message: fmt.Sprintf("配额预扣失败: %v", err)} } return remaining, nil } // Settle 结算:预扣转实耗(任务成功后)。 func (v *Verifier) Settle(keyID int64, now time.Time) error { return v.db.QuotaSettle(keyID, now) } // Release 释放预扣(任务失败回滚)。 func (v *Verifier) Release(keyID int64, now time.Time) error { return v.db.QuotaRelease(keyID, now) }