feat(relay):限流等错误情况不计入请求记录中

This commit is contained in:
qian committed 2026-08-05 00:50:20 +08:00
1 parent f118513c75
commit 2c53aa2576
1 file changed
+32 -22
+32 -22
View File
@@ -604,7 +604,7 @@ func RelayHandler(ctx context.Context, body []byte, path string, headers http.He
if billing != nil && preDeductAmount > 0 {
_ = billing.SettleFailed(settleCtx, rc.TenantID, rc.RequestID, preDeductAmount)
}
recordFailedUsage(provider, rc, selection.ChannelID, v.modelName, v.relayMode, v.isStream, err)
recordFailedUsage(provider, rc, selection, v.modelName, v.relayMode, v.isStream, err)
recordChannelError(rc, selection, v.modelName, attempt, true, err, info.LatencyMs())
finalizeTrace(trace, rc, hop, false, attempt, selection, err.Error(), info.LatencyMs())
return nil, v.billingResult, helper.RemapStatusCode(constant.NewUpstreamError(502, "upstream request failed", err), info.ChannelMeta.Settings.StatusCodeMapping)
@@ -646,7 +646,7 @@ func RelayHandler(ctx context.Context, body []byte, path string, headers http.He
billing.IncrApiKeyQuotaUsed(settleCtx, rc.ApiKeyID, settleResult.ActualCost)
}
}
recordFailedUsage(provider, rc, selection.ChannelID, v.modelName, v.relayMode, v.isStream, err)
recordFailedUsage(provider, rc, selection, v.modelName, v.relayMode, v.isStream, err)
finalizeTrace(trace, rc, hop, false, attempt, selection, err.Error(), info.LatencyMs())
return usage, v.billingResult, err
}
@@ -692,7 +692,7 @@ func RelayHandler(ctx context.Context, body []byte, path string, headers http.He
if billing != nil && preDeductAmount > 0 {
_ = billing.SettleFailed(settleCtx, rc.TenantID, rc.RequestID, preDeductAmount)
}
recordFailedUsage(provider, rc, selection.ChannelID, v.modelName, v.relayMode, v.isStream, err)
recordFailedUsage(provider, rc, selection, v.modelName, v.relayMode, v.isStream, err)
recordChannelError(rc, selection, v.modelName, attempt, true, err, info.LatencyMs())
finalizeTrace(trace, rc, hop, false, attempt, selection, err.Error(), info.LatencyMs())
return nil, v.billingResult, err
@@ -845,7 +845,7 @@ func handleChannelUnavailable(
fmt.Sprintf("all %d channels failed for model: %s", len(channelErrors), v.modelName),
constant.ErrAllChannelsFailed,
)
recordFailedUsage(provider, rc, 0, v.modelName, v.relayMode, v.isStream, allFailedErr)
recordFailedUsage(provider, rc, nil, v.modelName, v.relayMode, v.isStream, allFailedErr)
return &channelUnavailableResult{nil, v.billingResult, allFailedErr}
}
@@ -857,7 +857,9 @@ func handleChannelUnavailable(
g.Log().Stack(false).Warningf(ctx, "[RelayHandler] 无可用渠道: model=%s tenant=%d user=%d request=%s%s",
v.modelName, rc.TenantID, rc.UserID, rc.RequestID, diagSuffix)
noChErr := constant.NewChannelError("no available channel for model: "+v.modelName, err)
recordFailedUsage(provider, rc, 0, v.modelName, v.relayMode, v.isStream, noChErr)
// 无可用渠道时请求未转发到任何上游(与 QPS 限流、权限/额度拒绝等前置拦截同理),
// 不记用量日志,避免零消耗的 error 记录污染请求日志;运营侧的“被拒请求量”已由
// 上方 Warning 日志、调度器排除明细指标、chn_error_events 覆盖。
return &channelUnavailableResult{nil, v.billingResult, noChErr}
}
@@ -917,23 +919,31 @@ func (e *RelayErrorWithRateLimit) Error() string {
return e.Message
}
// recordFailedUsage 记录失败用量
func recordFailedUsage(provider common.DataProvider, rc *RelayContext, channelID int64, modelName string, relayMode constant.RelayMode, isStream bool, err error) {
provider.RecordUsage(context.Background(), &common.UsageRecord{
TenantID: rc.TenantID,
UserID: rc.UserID,
ApiKeyID: rc.ApiKeyID,
ProjectID: rc.ProjectID,
ChannelID: channelID,
ModelName: modelName,
RelayMode: int(relayMode),
LatencyMs: 0,
IsStream: isStream,
Success: false,
RequestID: rc.RequestID,
Status: "error",
ErrorMessage: err.Error(),
})
// recordFailedUsage 记录失败用量。
// selection 非 nil 时记录具体失败渠道(ID/名称/类型/上游模型),便于在用量日志定位失败渠道;
// nil 表示无单一渠道(全部渠道失败),渠道字段留空,失败详情见 error_message。
func recordFailedUsage(provider common.DataProvider, rc *RelayContext, selection *common.ChannelSelection, modelName string, relayMode constant.RelayMode, isStream bool, err error) {
record := &common.UsageRecord{
TenantID: rc.TenantID,
UserID: rc.UserID,
ApiKeyID: rc.ApiKeyID,
ProjectID: rc.ProjectID,
ModelName: modelName,
RequestedModel: modelName,
RelayMode: int(relayMode),
IsStream: isStream,
Success: false,
RequestID: rc.RequestID,
Status: "error",
ErrorMessage: err.Error(),
}
if selection != nil {
record.ChannelID = selection.ChannelID
record.ChannelName = selection.ChannelName
record.ChannelType = selection.ChannelType
record.UpstreamModel = selection.UpstreamModelName
}
provider.RecordUsage(context.Background(), record)
}
// recordChannelError 记录渠道错误事件到 chn_error_events(异步,不阻塞请求)