Skip to content

fix: drain streaming cancel tasks before completion#3690

Open
fallintoplace wants to merge 2 commits into
openai:mainfrom
fallintoplace:fix/streaming-cancel-drains-tasks
Open

fix: drain streaming cancel tasks before completion#3690
fallintoplace wants to merge 2 commits into
openai:mainfrom
fallintoplace:fix/streaming-cancel-drains-tasks

Conversation

@fallintoplace

Copy link
Copy Markdown
Contributor

Summary

  • keep immediate streaming cancel from marking the result complete synchronously
  • drain the owned run-loop/input/output guardrail tasks with a short bounded wait before final completion
  • preserve the immediate-cancel behavior that skips sandbox cleanup

Tests

  • uv run pytest tests/test_cancel_streaming.py::test_cancel_immediate_drains_owned_tasks_before_marking_complete tests/sandbox/test_runtime.py::test_runner_streamed_immediate_cancel_skips_waiting_for_sandbox_cleanup
  • uv run pytest tests/test_cancel_streaming.py
  • uv run ruff check src/agents/result.py tests/test_cancel_streaming.py

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9eb06ec020

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/agents/result.py
Comment on lines +757 to +760
elif self._cancel_mode == "immediate":
await self._drain_cancelled_tasks()
self._check_errors()
self.is_complete = True

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Mark timed-out streams complete after cancellation

When stream_events() itself is cancelled (for example an asyncio.wait_for(....__anext__()) timeout), the except asyncio.CancelledError path above calls self.cancel(), but cancelled stays true so this new immediate-cancel drain/completion branch is skipped. Since cancel() no longer sets is_complete synchronously and the final queue drain removes the sentinel it enqueued, a result whose run loop has not already posted its own sentinel can be left incomplete with an empty queue; following the documented advice to continue consuming stream_events() can then wait forever. Please also put the result into a terminal state in the cancelled path without blocking on the drain.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fd017a0b70

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/agents/result.py
Comment on lines +774 to 775
if not cancelled and self._cancel_mode != "immediate":
await self._run_sandbox_cleanup()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep sandbox cleanup alive after immediate cancel

When a sandboxed streamed run has already finished its run loop but is still in ensure_sandbox_cleanup_on_completion()'s wrapper awaiting _run_sandbox_cleanup(), calling cancel(mode="immediate") cancels run_loop_task; because that wrapper is awaiting the cleanup task, the cleanup task is cancelled too. This new guard then skips _run_sandbox_cleanup() in stream_events(), so runner-owned sandbox sessions can miss shutdown(), client delete(), and dependency close (for example, a fast model enqueues multiple events and the consumer cancels after the first event while cleanup is running). Immediate cancel should return promptly, but cleanup still needs to stay scheduled or be retried/shielded.

Useful? React with 👍 / 👎.

@seratch seratch changed the title Drain streaming cancel tasks before completion fix: drain streaming cancel tasks before completion Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants