From d10fc762fa4c1c3b59d4f6a6c0099f99f0230dd0 Mon Sep 17 00:00:00 2001 From: feitianbubu Date: Fri, 26 Jun 2026 21:48:23 +0800 Subject: [PATCH] fix(task): attribute async task usage log to the initiating node (#5684) Async task usage logs (LogQuotaData node dimension) were recorded under whichever node happened to poll the task to completion, not the node that submitted it. For token/adaptor-billed video tasks the pre-deduction is often 0, so the entire quota landed on the last polling node. Snapshot common.NodeName into TaskPrivateData at submit time and use it when writing the settlement consume log; fall back to the current node when empty so existing tasks stay compatible. --- controller/relay.go | 1 + model/log.go | 7 ++++++- model/task.go | 1 + service/task_billing.go | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/controller/relay.go b/controller/relay.go index 65fe6fbe..ee24100d 100644 --- a/controller/relay.go +++ b/controller/relay.go @@ -583,6 +583,7 @@ func RelayTask(c *gin.Context) { task.PrivateData.BillingSource = relayInfo.BillingSource task.PrivateData.SubscriptionId = relayInfo.SubscriptionId task.PrivateData.TokenId = relayInfo.TokenId + task.PrivateData.NodeName = common.NodeName task.PrivateData.BillingContext = &model.TaskBillingContext{ ModelPrice: relayInfo.PriceData.ModelPrice, GroupRatio: relayInfo.PriceData.GroupRatioInfo.GroupRatio, diff --git a/model/log.go b/model/log.go index 544638c8..7247184f 100644 --- a/model/log.go +++ b/model/log.go @@ -390,6 +390,7 @@ type RecordTaskBillingLogParams struct { TokenId int Group string Other map[string]interface{} + NodeName string // 任务发起节点;为空时回退当前节点 } func RecordTaskBillingLog(params RecordTaskBillingLogParams) { @@ -423,6 +424,10 @@ func RecordTaskBillingLog(params RecordTaskBillingLogParams) { common.SysLog("failed to record task billing log: " + err.Error()) } if params.LogType == LogTypeConsume && common.DataExportEnabled { + nodeName := params.NodeName + if nodeName == "" { + nodeName = common.NodeName + } gopool.Go(func() { LogQuotaData(QuotaDataLogParams{ UserID: params.UserId, @@ -433,7 +438,7 @@ func RecordTaskBillingLog(params RecordTaskBillingLogParams) { UseGroup: params.Group, TokenID: params.TokenId, ChannelID: params.ChannelId, - NodeName: common.NodeName, + NodeName: nodeName, }) }) } diff --git a/model/task.go b/model/task.go index 47316bd5..9c0cb6dd 100644 --- a/model/task.go +++ b/model/task.go @@ -104,6 +104,7 @@ type TaskPrivateData struct { BillingSource string `json:"billing_source,omitempty"` // "wallet" 或 "subscription" SubscriptionId int `json:"subscription_id,omitempty"` // 订阅 ID,用于订阅退款 TokenId int `json:"token_id,omitempty"` // 令牌 ID,用于令牌额度退款 + NodeName string `json:"node_name,omitempty"` // 发起任务的节点名,轮询结算阶段据此归属日志而非最后查询节点 BillingContext *TaskBillingContext `json:"billing_context,omitempty"` // 计费参数快照(用于轮询阶段重新计算) } diff --git a/service/task_billing.go b/service/task_billing.go index 6cf7a965..31e29e32 100644 --- a/service/task_billing.go +++ b/service/task_billing.go @@ -241,6 +241,7 @@ func RecalculateTaskQuota(ctx context.Context, task *model.Task, actualQuota int TokenId: task.PrivateData.TokenId, Group: task.Group, Other: other, + NodeName: task.PrivateData.NodeName, }) }