fix: 修复 CPA 用量与请求终态关联

This commit is contained in:
chuan
2026-08-16 02:51:04 +08:00
parent daf7e4ce61
commit 803251b08a
16 changed files with 895 additions and 20 deletions
+12 -6
View File
@@ -12,6 +12,7 @@ import (
"os"
"path/filepath"
"strings"
"sync"
"time"
"billing/internal/collection"
@@ -231,10 +232,10 @@ ON billing_ledger(managed_key_id, id DESC);
`
const (
// CLIProxyAPI UsageRecord currently has no RequestID. The usage and terminal
// callbacks nevertheless carry request-start timestamps from the same host
// execution, normally only a few milliseconds apart. This window is used
// only for the read projection and never changes persisted billing facts.
// Older CLIProxyAPI schemas have no RequestID in UsageRecord. Their usage and
// terminal callbacks nevertheless carry request-start timestamps from the
// same host execution, normally only a few milliseconds apart. This window
// is used only for the read projection and never changes persisted billing facts.
orphanLifecycleMatchWindow = 250 * time.Millisecond
// Near-equal candidates are deliberately left separate instead of risking a
// cross-request association under concurrent same-model traffic.
@@ -243,8 +244,9 @@ const (
// SQLiteUsageRepository 使用单写连接保存事实,并用独立连接池承载只读查询。
type SQLiteUsageRepository struct {
db *sql.DB
readDB *sql.DB
db *sql.DB
readDB *sql.DB
projectionMu sync.Mutex
}
func OpenSQLiteUsage(databasePath string) (*SQLiteUsageRepository, error) {
@@ -356,6 +358,8 @@ func sqliteDSN(databasePath string) (string, error) {
}
func (r *SQLiteUsageRepository) Insert(ctx context.Context, record collection.Record) error {
r.projectionMu.Lock()
defer r.projectionMu.Unlock()
eventKey := usageBillingEventKey(record)
tx, err := r.db.BeginTx(ctx, nil)
if err != nil {
@@ -468,6 +472,8 @@ UPDATE billing_cycles SET spent_micros=spent_micros+? WHERE managed_key_id=? AND
}
func (r *SQLiteUsageRepository) UpsertRequest(ctx context.Context, record collection.RequestRecord) error {
r.projectionMu.Lock()
defer r.projectionMu.Unlock()
requestID := strings.TrimSpace(record.RequestID)
if requestID == "" {
return errors.New("request_id 不能为空")