单二进制三角色 + Dock 适配器 + Swarm stack 达到可部署态;mgr1 实测订阅经 central-proxy bootstrap,探活 alive=41/52。 Co-authored-by: Cursor <cursoragent@cursor.com>
37 lines
1.3 KiB
Go
37 lines
1.3 KiB
Go
// 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)
|
||
}
|