Skip to content

fix(codex): reap subprocesses on early stream close - #4804

Open
Hughhhhcoder wants to merge 1 commit into
openai:mainfrom
Hughhhhcoder:codex/openai-agents-codex-exec-close
Open

fix(codex): reap subprocesses on early stream close#4804
Hughhhhcoder wants to merge 1 commit into
openai:mainfrom
Hughhhhcoder:codex/openai-agents-codex-exec-close

Conversation

@Hughhhhcoder

Copy link
Copy Markdown
Contributor

Summary

This pull request fixes CodexExec.run() hanging when a consumer closes its async output stream after receiving a line. The cleanup path previously awaited stderr EOF before killing a still-live Codex subprocess, even though that subprocess could keep stderr open indefinitely.

The finalizer now kills a live child before draining stderr and always awaits process.wait() so the child is reaped. A regression test covers the caller-visible early-close behavior without changing public APIs or normal stream semantics.

Test plan

  • OPENAI_AGENTS_TEST_IN_CODEX_SANDBOX=1 UV_DEFAULT_INDEX=https://pypi.org/simple bash .agents/skills/code-change-verification/scripts/run.sh (format, lint, typecheck, and full tests pass with the repository CI's uv 0.11.14)
  • uv run pytest -q tests/extensions/experiemental/codex/test_codex_exec_thread.py -k closes_live_process_before_draining_stderr (1 passed)

Issue number

N/A — found through source inspection.

Checks

  • I've added new tests, if relevant
  • I've run .agents/skills/code-change-verification/scripts/run.sh
  • I've confirmed all verification steps pass
  • If using Codex, I've run /review before submitting this PR

@Hughhhhcoder

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-01T09:40:53.931919Z cb7fa2b Manual request
🔒 Security Review Completed 2026-09-01T09:46:37.144146Z cb7fa2b Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: cb7fa2b91c

ℹ️ 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".

@chatgpt-codex-connector

Copy link
Copy Markdown

Security review completed. No security issues were found in this pull request.

Reviewed commit: cb7fa2b91c

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@sylvesterkaczmarek sylvesterkaczmarek 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.

I traced the early-close path through stdout iteration, generator finalization, stderr draining, and child reaping. Moving the live-child kill ahead of await stderr_task removes the deadlock: a consumer can close after receiving output even when the subprocess keeps stderr open indefinitely. The nested try/finally also preserves the important ownership invariant that process.wait() still runs if stderr draining raises, so the child is reaped rather than merely signalled.

The focused regression exercises the reachable failure mode at the async-generator boundary and checks both ordering (kill before stderr EOF) and final reaping. Normal completion remains unchanged because the kill is still conditional on returncode is None. I did not find a blocking issue in this change.

@Hughhhhcoder

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed review and for checking the early-close ordering and reaping invariant. I rechecked the current head and focused regression; no additional code change is needed from this review. I’ll leave the PR open for maintainer review.

@Hughhhhcoder

Copy link
Copy Markdown
Contributor Author

Follow-up validation: with uv 0.12.9, uv run --locked pytest tests/extensions/experiemental/codex/test_codex_exec_thread.py -q passes all 48 tests. The worktree remains clean and no source changes were needed for the review.

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