Skip to content

fix(aws): cancel Bedrock requests on client disconnect - #6589

Merged
Calcium-Ion merged 2 commits into
mainfrom
fix/aws-contex
Aug 1, 2026
Merged

fix(aws): cancel Bedrock requests on client disconnect#6589
Calcium-Ion merged 2 commits into
mainfrom
fix/aws-contex

Conversation

@Calcium-Ion

@Calcium-Ion Calcium-Ion commented Aug 1, 2026

Copy link
Copy Markdown
Member

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

📝 变更描述 / Description

AWS Bedrock 请求原先使用独立的后台 Context,客户端断开后,上游生成仍会继续,最终可能按照完整 Token 用量结算。

本次修改让 Bedrock SDK 请求继承客户端请求 Context,同时保留 RelayTimeout

  • 客户端断开时取消流式、非流式及 Nova 请求。
  • 流式请求监听 Context 取消并及时关闭 EventStream,不再读取取消后的最终 usage。
  • 客户端取消导致的初始调用错误停止重试;普通上游错误和独立的 RelayTimeout 保持原有重试行为。
  • 中断后的流仍执行 Anthropic finalizer,保留取消前的部分 usage 用于结算。
  • 调整 usage_billing_path 的日志判定,使审计标签与实际采用的 BillingUsage 一致,不改变计费数值。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 Issues 与 PRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

验证范围包括 Context 继承、客户端取消、重试控制、流关闭、部分 usage 保留及日志路径判定。

$ go test ./relay/channel/aws ./relay/channel/claude ./service
ok  github.com/QuantumNous/new-api/relay/channel/aws
ok  github.com/QuantumNous/new-api/relay/channel/claude
ok  github.com/QuantumNous/new-api/service

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Bug Fixes**
  * AWS requests now honor cancellation and configured timeouts across standard and streaming responses.
  * Canceled or timed-out requests are correctly treated as non-retryable.
  * Streaming responses stop cleanly on cancellation while preserving partial usage and billing details.
  * Billing paths now more accurately distinguish local, upstream, and estimated usage across supported providers.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

@cursor

cursor Bot commented Aug 1, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

AWS invocation lifecycle

Layer / File(s) Summary
AWS context and error propagation
relay/channel/aws/relay-aws.go, relay/channel/aws/relay_aws_test.go
AWS handlers derive contexts from incoming requests and use shared error classification. Tests cover cancellation, retry behavior, and SDK request termination.
AWS stream cancellation and usage
relay/channel/aws/relay-aws.go, relay/channel/aws/relay_aws_test.go
Streaming handlers stop on cancellation or channel closure, close the upstream stream, and preserve the specified partial or final usage behavior.

Billing path normalization

Layer / File(s) Summary
Normalized billing path resolution
service/billing_usage.go, service/text_quota_test.go
Billing path selection uses normalized usage data. Tests cover effective billing, estimated Gemini usage, and invalid Anthropic payload fallbacks.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant AWSHandler
  participant BedrockSDK
  participant EventStream

  Client->>AWSHandler: Send request with context
  AWSHandler->>BedrockSDK: Invoke using derived context
  BedrockSDK-->>AWSHandler: Return response or event stream
  EventStream-->>AWSHandler: Deliver chunks and usage
  Client-->>AWSHandler: Cancel request
  AWSHandler->>EventStream: Close upstream stream
  AWSHandler-->>Client: Stop output and finalize response
Loading

Suggested reviewers: yyhhyyyyyy

Poem

A rabbit hops through streams of light,
Cancels a call before the night.
Chunks are saved, the stream is closed,
Usage paths are neatly composed.
“Done,” says Bun, with ears held high.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: canceling AWS Bedrock requests when the client disconnects.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/aws-contex

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Calcium-Ion Calcium-Ion changed the title Fix/aws contex fix(aws): cancel Bedrock requests on client disconnect Aug 1, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@relay/channel/aws/relay_aws_test.go`:
- Line 448: Update the final body-length assertion in the cancellation test to
verify that responseWriter.Body.Len() is at least bodyLengthBeforeCancel, rather
than requiring exact equality. Keep the existing partial-usage and "[DONE]"
assertions unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: abbeff12-d2e9-42bc-ae14-35b8e32597c6

📥 Commits

Reviewing files that changed from the base of the PR and between cfaba1d and f04db28.

📒 Files selected for processing (4)
  • relay/channel/aws/relay-aws.go
  • relay/channel/aws/relay_aws_test.go
  • service/billing_usage.go
  • service/text_quota_test.go

assert.Equal(t, dto.BillingUsageSemanticAnthropic, result.usage.BillingUsage.Semantic)
assert.Equal(t, 100, result.usage.BillingUsage.ClaudeUsage.InputTokens)
assert.Equal(t, 1, result.usage.BillingUsage.ClaudeUsage.OutputTokens)
assert.Equal(t, bodyLengthBeforeCancel, responseWriter.Body.Len())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Relax the exact body-length assertion.

bodyLengthBeforeCancel is captured inside Flush at the moment the body first contains partial. The producer has already written all three initial events to the pipe at that point. The handler can therefore write further SSE frames before it observes ctx.Done(), so the final body length is not deterministic. This assertion can fail intermittently.

The invariants that matter are already covered by the partial-usage assertions and by assert.NotContains(..., "[DONE]"). Assert a lower bound instead of exact equality.

💚 Proposed change
-	assert.Equal(t, bodyLengthBeforeCancel, responseWriter.Body.Len())
+	assert.GreaterOrEqual(t, responseWriter.Body.Len(), bodyLengthBeforeCancel)

As per coding guidelines: "prefer deterministic table tests with explicit inputs and exact outputs, and avoid coverage-only, fake stress, timing, or implementation-detail tests".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
assert.Equal(t, bodyLengthBeforeCancel, responseWriter.Body.Len())
assert.GreaterOrEqual(t, responseWriter.Body.Len(), bodyLengthBeforeCancel)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@relay/channel/aws/relay_aws_test.go` at line 448, Update the final
body-length assertion in the cancellation test to verify that
responseWriter.Body.Len() is at least bodyLengthBeforeCancel, rather than
requiring exact equality. Keep the existing partial-usage and "[DONE]"
assertions unchanged.

Source: Coding guidelines

@Calcium-Ion
Calcium-Ion merged commit bd585d7 into main Aug 1, 2026
4 checks passed
0401lucky pushed a commit to 0401lucky/new-api that referenced this pull request Aug 2, 2026
)

* fix(aws): cancel Bedrock requests on client disconnect

* fix(billing): log effective usage billing path
bigfish9 added a commit to lanlingxiawu/new-api-er that referenced this pull request Aug 3, 2026
合并上游 16 个提交,主要是 token Auto 分组 (QuantumNous#6590)、deepseek responses API
(QuantumNous#6562)、Bedrock 客户端断开取消 (QuantumNous#6589)、分层重试计费加固 (QuantumNous#6518/QuantumNous#6570)、
zstd 请求解压 (QuantumNous#6545)、OIDC 自定义显示名 (QuantumNous#6012)、日志暴露 stream_status
(QuantumNous#6558)。

33 处冲突的处理:

- 11 个 legacy channel adaptor:上游删除 panic 之后的死代码以配合新增的
  go vet CI,本仓早已把整段 panic 换成返回 ErrLegacyAdaptorNotImplemented,
  已达成同一目的且不会让中继链路 panic,保留本仓实现。
- relay-aws.go 流式循环:两侧改动正交,合并保留 —— 上游的 ctx.Done() 取消
  分支(客户端断开时不再空转上游),加本仓的 finalizeClaudeOnError(提前
  返回时补发流终止符,否则 Claude 格式调用方会一直挂着)。
- 7 个 locale:两侧各自插入相邻 key,按字母序归并;上游 24 个新 key 与本仓
  1278 个 fork key 全部保留,逐一核对无丢失。
- keys / oauth / profile 前端:上游 Auto 分组为主体,叠加本仓改动;
  account-bindings-tab 与 oauth/$provider 保留本仓实现,理由见下。

测试取舍:

- 不引入 model/token_auto_groups_cache_test.go:它依赖上游的 truncateTables,
  该助手全局清表,与本仓行级清理原则冲突(共享库里有开发数据)。
- 不携带上游 controller/token_test.go:其迁移兼容测试会替换 model.DB 并在
  cleanup 里关闭,后续用 harness 连接的测试会拿到已关闭的句柄。按既有约定,
  token_auto_groups_test.go 需要的四个助手放进 zz_upstream_test_shims_test.go,
  其中 openTokenControllerTestDB 增加了 model.DB/LOG_DB 的成对保存还原。
  本仓原 token_test.go 的 controller 行为测试迁到
  gen_ctrl_token_handlers_test.go,与上游文件名脱钩以免再冲突。
- 三处断言随上游行为更新:stream_status 现对日志所有者可见;deepseek 的
  ConvertOpenAIResponsesRequest 已实现不再返回错误;计费路径判定收紧为
  「标记之外还需带对应 usage payload」,并补了三个反向用例锁住该语义。

遗留:oauth 绑定回调仍用 window.opener 判定 bind/login,上游 QuantumNous#6425 已改为
sessionStorage 标记 + state 比对。该修复要求 popup 先以 about:blank 打开再打
标记,本仓四个内置 provider 走 window.open(url) 直开,直接套用会让绑定永远
判成 login,故本次未采纳,需单独改造。
speedxcc pushed a commit to speedxcc/new-api-speed that referenced this pull request Aug 4, 2026
合并官方上游 Calcium-Ion/new-api main 分支的 10 个新 commit:
- Feat/auto group (QuantumNous#6590)
- fix(aws): cancel Bedrock requests on client disconnect (QuantumNous#6589)
- fix(billing): harden tiered retry group-switch billing (QuantumNous#6570)
- fix(billing): settle tiered retries with final group (QuantumNous#6518)
- feat: deepseek responses api (QuantumNous#6562)
- fix(oauth): stop treating a foreign window.opener as a bind flow (QuantumNous#6425)
- fix(relay): preserve multipart image edits for New API channels (QuantumNous#6559)
- feat(logs): expose stream status to log owners (QuantumNous#6558)
- feat: support zstd request decompression (QuantumNous#6545)
- style: use text-sm for public header nav links (QuantumNous#6557)

冲突解决: model/option.go 的 switch case 区域,双方各自新增了选项注册
(我方 GroupPassThrough + 官方 MaxTokenAutoGroups),取并集保留两者。
其余文件均自动合并成功。

验证: go build + go test 全过(relay/helper、middleware、controller)
youngshunf added a commit to youngshunf/new-api that referenced this pull request Aug 6, 2026
…s / 84 files)

上游本次内容:
- Feat/auto group (QuantumNous#6590):令牌自动分组(含前端 auto-group 编排 UI 与后端组选择)
- fix(aws): Bedrock 请求在客户端断连时取消 (QuantumNous#6589)
- fix(relay): 设置 Request.GetBody,让 HTTP/2 传输在上游 stream reset 后可透明重试 (QuantumNous#6249)
- refactor(relay): 把 replay 元数据移到请求体上(RelayInfo.UpstreamRequestBodySize 移除)

冲突 1 处,纯新增函数相邻,两侧保留:
- relay/channel/api_request.go:我方 upstreamRequestIDFromHeaders 与上游 keepUpstreamRedirectResponse
yiranxiaohui added a commit to yiranxiaohui/new-api that referenced this pull request Aug 7, 2026
Brings in from QuantumNous/new-api:
- fix: 修复兑换码额度精度损失 (QuantumNous#6685)
- feat(rate-limit): user critical rate limit for access token and aff transfer routes
- fix: test Claude/Gemini endpoints with native request format (QuantumNous#6698)
- feat(channels): refine fetched model categorization (QuantumNous#6632)
- security: atomic access-token rotation and aff updates (merge commit from fork)
- refactor(relay): move replay metadata onto request bodies
- fix(relay): set Request.GetBody for transparent HTTP/2 retry (QuantumNous#6249)
- Feat/auto group (QuantumNous#6590)
- fix(aws): cancel Bedrock requests on client disconnect (QuantumNous#6589)

Conflicts resolved:
- controller/model.go: adopt upstream's unified group-model loop with
  FormatMatchingModelName token-limit matching; keep fork's
  hiddenMappedModels filter inside the loop
- model/user.go: keep fork's BatchDeleteUsers; adopt upstream's atomic
  gorm.Expr-based inviteUser
- relay/channel/task/sora/adaptor_test.go: keep both fork's New API
  Video channel tests and upstream's replayable-body test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZteapnbTWdP52n7wZ6NsN
yuqiyi pushed a commit to yuqiyi/new-api that referenced this pull request Aug 16, 2026
* v1.0.0-rc.24: (117 commits)
  CI: enhance release synchronization workflow with optional file syncing
  fix: 修复兑换码额度精度损失 (QuantumNous#6685)
  feat(rate-limit): add user critical rate limit middleware for access token and aff transfer routes
  fix: test Claude/Gemini endpoints with native request format (QuantumNous#6698)
  feat(channels): refine fetched model categorization (QuantumNous#6632)
  Merge commit from fork
  refactor(relay): move replay metadata onto request bodies
  fix(relay): set Request.GetBody so the HTTP/2 transport can transparently retry after an upstream stream reset (QuantumNous#6249)
  Feat/auto group (QuantumNous#6590)
  fix(aws): cancel Bedrock requests on client disconnect (QuantumNous#6589)
  fix(billing): harden tiered retry group-switch billing (QuantumNous#6570)
  fix(billing): settle tiered retries with final group (QuantumNous#6518)
  feat: deepseek responses api (QuantumNous#6562)
  style: use text-sm for public header nav links to match other nav components (QuantumNous#6557)
  fix(oauth): stop treating a foreign window.opener as a bind flow (QuantumNous#6425)
  fix(relay): preserve multipart image edits for New API channels (QuantumNous#6559)
  feat(logs): expose stream status to log owners (QuantumNous#6558)
  feat: support zstd request decompression (QuantumNous#6545)
  fix: preserve Qwen thinking_budget passthrough (QuantumNous#5836)
  feat(oidc): 支持自定义 OIDC 登录显示名称 (QuantumNous#6012)
  ...

# Conflicts:
#	service/text_quota.go
#	web/src/features/models/components/drawers/model-mutate-drawer.tsx
#	web/src/features/pricing/components/model-details.tsx
#	web/src/features/pricing/lib/price.ts
refeiner pushed a commit to wuqiang44444444/new-api that referenced this pull request Aug 17, 2026
)

* fix(aws): cancel Bedrock requests on client disconnect

* fix(billing): log effective usage billing path
330079598 pushed a commit to 330079598/new-api that referenced this pull request Aug 19, 2026
)

* fix(aws): cancel Bedrock requests on client disconnect

* fix(billing): log effective usage billing path
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant