fix: 修复 CPA 用量与请求终态关联
This commit is contained in:
@@ -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 不能为空")
|
||||
|
||||
Reference in New Issue
Block a user