Skip to content

fix: make app-server connection loss terminal - #685

Open
seungpyoson wants to merge 1 commit into
openai:mainfrom
seungpyoson:fix/app-server-terminal-lifecycle
Open

fix: make app-server connection loss terminal#685
seungpyoson wants to merge 1 commit into
openai:mainfrom
seungpyoson:fix/app-server-terminal-lifecycle

Conversation

@seungpyoson

Copy link
Copy Markdown

Summary

  • make app-server connection loss a single terminal transition that rejects pending RPCs, future RPCs, and turn-completion waiters
  • bound initialization and owned-child teardown without adding a production turn-duration timeout
  • make broker shutdown idempotent and able to close half-open clients and reap failed-startup processes
  • add behavioral coverage for parse failures, non-object messages, EOF, write failures, early child exit, process-tree cleanup, and shutdown races

Motivation

The app-server client previously tracked logical protocol failure separately from process closure. Several connection-loss paths could therefore leave later requests or turn-completion waits unsettled, and initialization failure could return without reaping the owned launcher tree.

This change gives the connection one write-once terminal cause and routes every relevant protocol or process failure through it. Initialization and teardown have bounded lifecycle deadlines; normal Codex turns remain unbounded.

Testing

  • npm test (106 tests)
  • npm run build

@seungpyoson
seungpyoson requested a review from a team August 25, 2026 13:35

@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: a01a9f8bcf

ℹ️ 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 tests/runtime.test.mjs
assert.ok(firstSession);
const firstEndpoint = parseBrokerEndpoint(firstSession.endpoint);
await waitFor(
() => !processIsAlive(firstSession.pid) && (firstEndpoint.kind !== "unix" || !fs.existsSync(firstEndpoint.path)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Treat zombie broker processes as terminated

On Linux containers where PID 1 does not reap orphaned children, the detached broker becomes a zombie after exiting, so process.kill(pid, 0) continues to succeed indefinitely even though the endpoint has been removed. This makes the new lifecycle test consistently time out at this condition; npm test fails in this environment. Check the process state or rely on endpoint/session cleanup rather than requiring processIsAlive() to return false.

Useful? React with 👍 / 👎.

env: this.options.env ?? process.env,
stdio: ["pipe", "pipe", "pipe"],
shell: process.platform === "win32" ? (process.env.SHELL || true) : false,
detached: process.platform !== "win32",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep the app server in the broker process group

On POSIX, the broker is already detached into its own process group, and setting detached: true again gives the app-server child a separate group. If the broker is forcibly terminated—for example by failed-session teardown or an external SIGKILLterminateProcessTree(brokerPid) no longer reaches Codex, leaving the app server and any descendants running without a broker; direct callers interrupted by terminal SIGINT can leak it for the same reason. Preserve group-level ownership so terminating the owning process tree also terminates Codex.

Useful? React with 👍 / 👎.

Comment on lines +281 to +284
this.proc.stdout.on("end", () => {
if (!this.terminalCause) {
this.transitionToTerminal(createProtocolError("codex app-server stdout closed before the connection ended."));
}

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 Preserve the child exit error when stdout closes

When the spawned Codex process exits with a startup, authentication, or configuration error, its stdout end event normally arrives before the child exit event. This handler therefore locks in the generic stdout-closed terminal cause, and the later exit handler cannot replace it with the exit code and captured stderr; a direct reproduction with a child exiting nonzero reports only codex app-server stdout closed before the connection ended. Defer the EOF diagnosis until the child exit status is available so users retain the actionable failure.

Useful? React with 👍 / 👎.

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