feat: 金额 decimal 精确计费、failover 按失败类型封顶、渠道小时桶预聚合、分层守护测试
- 计费:19 个金额字段 float64→decimal.Decimal,DB 列保持 numeric(20,8) 零迁移; API 金额仍为 JSON number(MarshalJSONWithoutQuotes),前端零改动 - failover:保留时间预算,新增 OT_PROXY_FAILOVER_CAPS_NET/SERVER/RATE/QUOTA 按失败类型封顶换渠道次数(429/配额类瞬时失败时间预算形同虚设) - 预聚合:新增 usage_channel_hourlies(schema v10),记账事务内同步 upsert, 长窗口渠道统计走桶不再扫明细,spent_last_30d 改扫 usage_daily,v10 一次性回填幂等 - 守护:internal/arch_test.go 用 go/parser 强制分层依赖(fail-closed)
This commit is contained in:
1 parent
5d6e5bdb04
commit
b2e500ff51
25 files changed
+841
-253
No files matched your search
@@ -1,7 +1,6 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"math"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
@@ -9,6 +8,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/openteam/server/internal/store"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
// runPath 走完整链路(Auth → Handle),路径与请求体由调用方给。
|
||||
@@ -54,8 +54,8 @@ func TestUsageReasoningAndServedModelRecorded(t *testing.T) {
|
||||
t.Fatalf("reasoning_tokens 应为 3,实际 %d", l.ReasoningTokens)
|
||||
}
|
||||
// 计费不含 reasoning 加成:10×0.15/1e6 + 5×0.6/1e6 = 4.5e-6
|
||||
if math.Abs(l.Cost-4.5e-6) > 1e-12 {
|
||||
t.Fatalf("cost 应为 4.5e-6(reasoning 不重复计费),实际 %g", l.Cost)
|
||||
if !l.Cost.Equal(decimal.NewFromFloat(4.5e-6)) {
|
||||
t.Fatalf("cost 应为 4.5e-6(reasoning 不重复计费),实际 %s", l.Cost)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,9 +100,13 @@ func TestAnthropicCache1hBillingSplit(t *testing.T) {
|
||||
t.Fatalf("served_model 应为 claude-x,实际 %q", l.ServedModel)
|
||||
}
|
||||
// 100/1e6*1 + 10/1e6*2 + 200/1e6*0.1 + 100/1e6*1.25 + 200/1e6*(1.25*1.6) = 6.65e-4
|
||||
want := 100.0/1e6*1.0 + 10.0/1e6*2.0 + 200.0/1e6*0.1 + 100.0/1e6*1.25 + 200.0/1e6*2.0
|
||||
if math.Abs(l.Cost-want) > 1e-9 {
|
||||
t.Fatalf("cost 应为 %g(1h/5m 分开计价),实际 %g", want, l.Cost)
|
||||
million := decimal.NewFromInt(1e6)
|
||||
want := decimal.NewFromInt(100).Div(million).Add(decimal.NewFromInt(10).Mul(decimal.NewFromFloat(2)).Div(million)).
|
||||
Add(decimal.NewFromInt(200).Mul(decimal.NewFromFloat(0.1)).Div(million)).
|
||||
Add(decimal.NewFromInt(100).Mul(decimal.NewFromFloat(1.25)).Div(million)).
|
||||
Add(decimal.NewFromInt(200).Mul(decimal.NewFromFloat(2.0)).Div(million))
|
||||
if !l.Cost.Equal(want) {
|
||||
t.Fatalf("cost 应为 %s(1h/5m 分开计价),实际 %s", want, l.Cost)
|
||||
}
|
||||
// 落库 input 为含缓存的总量口径
|
||||
if l.InputTokens != 600 || l.OutputTokens != 10 {
|
||||
|
||||
Reference in new issue
Block a user