Skip to content

fix(cluster): harden worker thread lifecycle - #6043

Open
gxkl wants to merge 6 commits into
nextfrom
codex/cluster-worker-runtime-followup
Open

fix(cluster): harden worker thread lifecycle#6043
gxkl wants to merge 6 commits into
nextfrom
codex/cluster-worker-runtime-followup

Conversation

@gxkl

@gxkl gxkl commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Hardens the worker_threads cluster lifecycle on top of the bundle and startup-snapshot support merged in #6042:

  • add an explicit master-to-worker graceful-exit message instead of attempting asynchronous cleanup from the worker exit event;
  • wait for app/agent cleanup and fall back to Worker.terminate() after the configured timeout;
  • consume and log worker error events during graceful shutdown, then continue with the termination fallback without exposing an unhandled EventEmitter error;
  • reject sticky: true with startMode: worker_threads, because sticky socket handoff requires process IPC;
  • preserve the existing master-port and reusePort listen semantics, with focused server-error and hostname regression coverage.

Why

A worker thread's exit event is emitted after the thread has already stopped, so cleanup cannot reliably be initiated from that event. The new protocol asks the worker to close while it is still alive and keeps forced termination as a bounded fallback.

Sticky mode is rejected explicitly because its socket handoff mechanism is only available to process workers.

Validation

  • ut run test --workspace @eggjs/cluster -- test/worker-thread-utils.test.ts test/worker-protocol.test.ts test/worker-protocol-io.test.ts — 24 passed
  • vitest run test/options.test.ts -t 'should reject sticky mode with worker_threads' — 1 passed
  • ut run typecheck --workspace @eggjs/cluster — passed

The full cross-platform suite is covered by CI.

Summary by CodeRabbit

  • New Features

    • Worker threads now shut down gracefully, allowing application and agent cleanup to complete before termination.
    • Shutdown automatically falls back to forced termination when the configured timeout is exceeded.
    • Added clear handling and logging for shutdown failures.
  • Bug Fixes

    • Sticky-session mode now rejects unsupported worker-thread startup configurations.
    • Improved worker port handling when the master port is set to zero.
  • Documentation

    • Documented worker-thread shutdown behavior and supported startup configurations.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bc9a4b39-adea-4369-ab0c-a251c4341d0c

📥 Commits

Reviewing files that changed from the base of the PR and between 38128f3 and 242d90b.

📒 Files selected for processing (4)
  • packages/cluster/src/utils/mode/impl/worker_threads/app.ts
  • packages/cluster/src/worker_protocol/worker-thread.ts
  • packages/cluster/test/worker-protocol-io.test.ts
  • packages/cluster/test/worker-thread-utils.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/cluster/src/worker_protocol/worker-thread.ts
  • packages/cluster/test/worker-protocol-io.test.ts
  • packages/cluster/test/worker-thread-utils.test.ts
  • packages/cluster/src/utils/mode/impl/worker_threads/app.ts

📝 Walkthrough

Walkthrough

Worker threads now support explicit graceful shutdown. Utilities wait for cleanup or a timeout, then terminate workers when required. Sticky mode is rejected with worker-thread startup, and related protocol, integration, and documentation coverage was added.

Changes

Worker-thread shutdown

Layer / File(s) Summary
Graceful-exit protocol
packages/cluster/src/worker_protocol/worker-thread.ts, packages/cluster/test/fixtures/worker-thread-io.mjs, packages/cluster/test/worker-protocol-io.test.ts
Workers handle WORKER_THREAD_GRACEFUL_EXIT, await beforeExit, ignore duplicate requests, and exit with status 0 or 1.
Timed shutdown orchestration
packages/cluster/src/utils/mode/impl/worker_threads/*.ts, packages/cluster/test/worker-thread-utils.test.ts
Agent and app utilities request graceful exit, wait for exit or timeout, log errors, and terminate overdue workers.
Startup and integration validation
packages/cluster/src/utils/options.ts, packages/cluster/src/worker_protocol/app.ts, packages/cluster/test/options.test.ts, packages/cluster/test/worker-protocol.test.ts
Sticky mode is rejected for worker-thread startup. Tests cover port fallback, reuse-port setup, listening errors, and graceful worker exit.
Shutdown documentation
wiki/log.md, wiki/packages/egg-bundler.md
Documentation describes awaited worker cleanup and timeout-based termination.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ShutdownUtility
  participant WorkerThread
  participant CleanupHandler
  ShutdownUtility->>WorkerThread: post WORKER_THREAD_GRACEFUL_EXIT
  WorkerThread->>CleanupHandler: await beforeExit
  CleanupHandler-->>WorkerThread: cleanup completes or fails
  WorkerThread-->>ShutdownUtility: exit event
  ShutdownUtility->>WorkerThread: terminate after timeout
Loading

Possibly related PRs

  • eggjs/egg#6042: Directly extends the worker-thread shutdown logic in the same implementation files.

Suggested reviewers: copilot, killagu

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the primary changes to harden the cluster worker-thread lifecycle.
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.
✨ 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 codex/cluster-worker-runtime-followup

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.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 5, 2026

Copy link
Copy Markdown

Deploying egg-v3 with  Cloudflare Pages  Cloudflare Pages

Latest commit: 242d90b
Status: ✅  Deploy successful!
Preview URL: https://e959bda5.egg-v3.pages.dev
Branch Preview URL: https://codex-cluster-worker-runtime.egg-v3.pages.dev

View logs

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 5, 2026

Copy link
Copy Markdown

Deploying egg with  Cloudflare Pages  Cloudflare Pages

Latest commit: 242d90b
Status: ✅  Deploy successful!
Preview URL: https://477ef7cc.egg-cci.pages.dev
Branch Preview URL: https://codex-cluster-worker-runtime.egg-cci.pages.dev

View logs

@gxkl
gxkl force-pushed the codex/cluster-worker-runtime-followup branch from 13ce99a to 0a81b31 Compare August 5, 2026 08:47
@gxkl
gxkl force-pushed the codex/snapshot-cluster-integration branch from bed5490 to 7ed8296 Compare August 7, 2026 04:15
Base automatically changed from codex/snapshot-cluster-integration to next August 7, 2026 06:07
@gxkl
gxkl force-pushed the codex/cluster-worker-runtime-followup branch from 0a81b31 to 38128f3 Compare August 7, 2026 06:22
@gxkl
gxkl marked this pull request as ready for review August 7, 2026 06:22
Copilot AI lite review requested due to automatic review settings August 7, 2026 06:22
@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.56098% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 83.43%. Comparing base (3a3bc65) to head (242d90b).

Files with missing lines Patch % Lines
.../cluster/src/utils/mode/impl/worker_threads/app.ts 94.11% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             next    #6043      +/-   ##
==========================================
+ Coverage   83.08%   83.43%   +0.34%     
==========================================
  Files         730      730              
  Lines       22474    22500      +26     
  Branches     4520     4524       +4     
==========================================
+ Hits        18673    18773     +100     
+ Misses       3297     3226      -71     
+ Partials      504      501       -3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI 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.

Pull request overview

This PR strengthens @eggjs/cluster shutdown behavior when running in worker_threads mode by switching to an explicit master→worker graceful-exit protocol (with a timeout and termination fallback), tightening invalid option combinations, and extending protocol coverage tests and docs.

Changes:

  • Implement master-driven worker-thread graceful shutdown via a dedicated close message, waiting for app/agent cleanup and falling back to Worker.terminate() on timeout.
  • Reject sticky: true when startMode: "worker_threads" (sticky handoff requires process IPC).
  • Add/extend tests and documentation for worker-thread shutdown and port/reusePort semantics (including server error cases).

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
wiki/packages/egg-bundler.md Document worker-thread shutdown protocol and sticky-session limitation in worker_threads mode.
wiki/log.md Update changelog note to reflect worker-thread graceful shutdown behavior.
packages/cluster/test/worker-thread-utils.test.ts Add new unit tests for worker-thread kill/graceful-exit/terminate fallback behavior.
packages/cluster/test/worker-protocol.test.ts Add protocol coverage for worker-thread cleanup and port/hostname/error scenarios.
packages/cluster/test/worker-protocol-io.test.ts Extend IO adapter tests to cover graceful-exit message handling and failure path.
packages/cluster/test/options.test.ts Add regression test ensuring sticky+worker_threads is rejected.
packages/cluster/test/fixtures/worker-thread-io.mjs Fixture now registers gracefulExit to validate worker-thread cleanup sequencing.
packages/cluster/src/worker_protocol/worker-thread.ts Introduce WORKER_THREAD_GRACEFUL_EXIT and implement message-triggered graceful exit.
packages/cluster/src/worker_protocol/app.ts Clarify master-port 0 semantics and expand listening behaviors covered by tests.
packages/cluster/src/utils/options.ts Enforce sticky-session incompatibility with worker_threads startMode.
packages/cluster/src/utils/mode/impl/worker_threads/app.ts Implement graceful shutdown + timeout fallback for app workers in worker_threads mode.
packages/cluster/src/utils/mode/impl/worker_threads/agent.ts Implement graceful shutdown + timeout fallback for agent worker in worker_threads mode.

Comment on lines +147 to +161
const id = Reflect.get(worker, 'id');
this.log(`[master] gracefully close app worker#${id} (worker_threads)`);
worker.removeAllListeners();
const exited = once(worker, 'exit').then(
() => true,
(err) => {
this.logger.error('[master] app worker#%s error during graceful shutdown: ', id, err);
return false;
},
);
worker.postMessage(WORKER_THREAD_GRACEFUL_EXIT);
if (!(await Promise.race([exited, sleep(timeout).then(() => false)]))) {
this.log(`[master] terminate app worker#${id} after ${timeout}ms timeout`);
await worker.terminate();
}
}
process.exit(0);
} catch (err) {
options.logger?.error('[worker_thread] graceful exit failed: %s', err);

Copilot AI 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.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

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