diff --git a/relay/helper/stream_scanner.go b/relay/helper/stream_scanner.go index a9bc5e16a720..c76dbfb30125 100644 --- a/relay/helper/stream_scanner.go +++ b/relay/helper/stream_scanner.go @@ -224,14 +224,14 @@ func StreamScannerHandler(c *gin.Context, resp *http.Response, info *relaycommon for scanner.Scan() { // 检查是否需要停止 + // 不监听 c.Request.Context().Done():客户端断连不应中断上游读取, + // 否则拿不到最后的 usage 事件(如 message_delta),导致计费缺失。 + // 上游响应流会自然结束(EOF/[DONE]),streaming timeout 兜底防止无限阻塞。 select { case <-stopChan: return case <-ctx.Done(): return - case <-c.Request.Context().Done(): - info.StreamStatus.SetEndReason(relaycommon.StreamEndReasonClientGone, c.Request.Context().Err()) - return default: } @@ -282,13 +282,13 @@ func StreamScannerHandler(c *gin.Context, resp *http.Response, info *relaycommon }) // 主循环等待完成或超时 + // 不监听 c.Request.Context().Done():客户端断连不应终止流程, + // scanner 会继续读完上游流拿到 usage,然后通过 stopChan 通知主循环退出。 select { case <-ticker.C: info.StreamStatus.SetEndReason(relaycommon.StreamEndReasonTimeout, nil) case <-stopChan: // EndReason already set by the goroutine that triggered stopChan - case <-c.Request.Context().Done(): - info.StreamStatus.SetEndReason(relaycommon.StreamEndReasonClientGone, c.Request.Context().Err()) } if info.StreamStatus.IsNormalEnd() && !info.StreamStatus.HasErrors() {