Skip to content

fix(trace): prevent false FetchResponse cancellation after normal completion - #1438

Open
SAzwj wants to merge 1 commit into
alibaba:mainfrom
SAzwj:feature/fix-fetchresponse-client-status
Open

SAzwj wants to merge 1 commit into
alibaba:mainfrom
SAzwj:feature/fix-fetchresponse-client-status

Conversation

@SAzwj

@SAzwj SAzwj commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

Master BATCH + P/D requests can complete successfully while the FetchResponse CLIENT span reports CANCELLED: upstream teardown cancels the pending gRPC EOF read after the terminal application frame.

Transfer that read to a shielded task before yielding the terminal frame, and finalize the span using the actual RPC status. Preserve cancellation before completion, late RPC errors, and bounded cleanup. Use the same transport cleanup with tracing disabled.

Validation:

  • RPC client, Dash inference, and proxy Bazel targets passed twice on CUDA 12.9 (one existing RPC test skip per run).
  • Real gRPC regressions cover two concurrent requests, terminal-frame teardown, early cancellation, and late CANCELLED, DEADLINE_EXCEEDED, and INTERNAL statuses.
  • The normal-completion regression reproduces CANCELLED on the previous implementation.

response_stream = response_iterator.__aiter__()
while True:
if terminal_read_task is None:
response = await _read_rpc_response(response_stream)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] trace 关闭(client_span=None)时 settlement 路径首次在无 span 下激活,需确认对 None 的处理

补丁将条件由 client_span is not None 改为 client_span is not None or terminal_seen(补丁 + 行 1087-1089),同时 client_settlement_abandoned 的创建条件改为 client_span is not None or use_fetch_response(补丁 + 行 1053)。当 trace 关闭但 use_fetch_response=True 时,terminal_seen 为真会使 _engine_reported_finished 块执行,settlement task 可能在 client_span=None 时被创建。若该块内创建 client_settlement_task 或 _settle_client_span_after_rpc 未对 client_span=None 做防护,会触发 AttributeError(补丁内看不到该块函数体,无法确认)。

建议:确认 _engine_reported_finished 块内 settlement task 的创建处及 _settle_client_span_after_rpc 对 client_span=None 的处理;若未防护,补充 None 判断或仅在 client_span is not None 时创建 settlement task。

评审版本:69e9a58c71f8

for close_at_frame in (False, True):
with self.subTest(
trace_enabled=trace_enabled, close_at_frame=close_at_frame
):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] 缺少 trace_enabled=False 且 RPC 延迟错误的测试覆盖

test_fetch_response_terminal_read_preserves_late_rpc_errors 仅以默认 trace_enabled=True 循环 status,未覆盖 client_span 为 None 时(trace 关闭)的延迟 RPC 错误路径;而本次改动专门扩展了 client_span is None 或 terminal_seen 的结算逻辑,该分支缺少回归测试。

建议:为该测试增加 trace_enabled=False 的 subTest,验证 trace 关闭时 late RPC error 仍被正确处理,或明确该场景不要求传播错误。

评审版本:69e9a58c71f8

@@ -1186,14 +1212,14 @@ async def enqueue(
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] terminal_read_task 在 finally 及异常路径中未被取消或等待,异常可能未被消费

finally 块(补丁 + 行 1214-1219)仅调用 client_settlement_abandoned.set(),从不 cancel/await terminal_read_task;而 _read_rpc_response(补丁 + 行 129-133)只捕获 StopAsyncIteration,服务器以非 OK 状态 abort 时(测试 test_fetch_response_terminal_read_preserves_late_rpc_errors 覆盖 CANCELLED/DEADLINE_EXCEEDED/INTERNAL)AioRpcError 会进入 terminal_read_task。若消费者在 finished 帧后立即关闭生成器(GeneratorExit),该 task 脱离事件循环,异常仅能靠 add_done_callback(_consume_settlement_task)(补丁 + 行 1095-1096)消费;若该回调未显式调用 task.exception()/result(),会产生 “Task exception was never retrieved” 告警并可能滞留资源。

建议:在 finally 中显式处理 terminal_read_task:若未完成则取消或确保其异常被消费(例如在 _consume_settlement_task 内无条件取出 exception),避免未检索异常告警;并补充注释说明该 task 的生命周期归属。

评审版本:69e9a58c71f8

self.assertIsInstance(result, asyncio.CancelledError)
servicer.release.set()
expected = status if finished else StatusCode.CANCELLED
for call in calls:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] 测试未覆盖 close_at_frame=True 与服务端错误状态的组合

test_fetch_response_terminal_read_survives_consumer_teardown 仅覆盖 StatusCode.OK 下的 trace_enabled×close_at_frame 四种组合;test_fetch_response_terminal_read_preserves_late_rpc_errors 使用默认参数(close_at_frame=False)覆盖 CANCELLED/DEADLINE_EXCEEDED/INTERNAL。缺少"消费者在 finished frame 处 aclose + 服务端随后 abort"的组合,而该组合正是本 PR 核心修复点(terminal read 在消费者关闭后仍需保留迟到错误并通过 done callback 正确结算 span)的关键路径,也是验证 _consume_settlement_task 复用是否正确的唯一场景。

建议:在 test_fetch_response_terminal_read_preserves_late_rpc_errors 中增加 close_at_frame=True(及 trace_enabled=False)的子测试,验证消费者关闭后 terminal_read_task 抛出的迟到 RPC 错误仍被正确结算到 span(status=ERROR、end_count=1)。

评审版本:69e9a58c71f8

@rtp-llm-review-bot

rtp-llm-review-bot commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

PR #1438 评审:未发现阻塞项,等待人工审核

  • 标题:fix(trace): prevent false FetchResponse cancellation after normal completion(@SAzwj,open)
  • 评审版本:69e9a58c71f8

无阻塞项

非阻塞发现


自动代码评审 · head 69e9a58c71f8 · 未发现阻塞项,等待人工审核

@rtp-llm-review-bot rtp-llm-review-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

lgtm ready to ci

评审版本:69e9a58c71f80e3d429f74d6132096b6c2482f79

@rtp-llm-review-bot
rtp-llm-review-bot dismissed their stale review September 23, 2026 03:53

自动评审结论已更新,此前的通过结论不再适用。

This branch has not been deployed

No deployments
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.

2 participants