Skip to content

Conversation

@fengmk2
Copy link
Member

@fengmk2 fengmk2 commented Dec 30, 2025

Add SO_REUSEPORT socket option support for server listen, which allows multiple server sockets to bind to the same port with the OS distributing incoming connections. This improves load balancing in cluster scenarios.

  • Add reusePort option to ClusterOptions interface
  • Add platform validation (linux, freebsd, sunos, aix)
  • Use server.listen({ port, reusePort, host }) when reusePort is enabled
  • Handle message routing for reusePort (cluster doesn't emit 'listening' event)
  • Support reusePort in worker_threads mode (all workers share same port)
  • Add test fixtures and tests for reusePort functionality

Synced from eggjs/cluster#115

close #5728

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added reusePort configuration option for cluster server listening. When enabled on supported platforms, this allows multiple workers to bind to the same port, improving socket reuse behavior and resource utilization (default: false).
  • Tests

    • Added test coverage and fixture applications for reusePort functionality.

✏️ Tip: You can customize this high-level summary in your review settings.

Add SO_REUSEPORT socket option support for server listen, which allows
multiple server sockets to bind to the same port with the OS distributing
incoming connections. This improves load balancing in cluster scenarios.

- Add reusePort option to ClusterOptions interface
- Add platform validation (linux, freebsd, sunos, aix)
- Use server.listen({ port, reusePort, host }) when reusePort is enabled
- Handle message routing for reusePort (cluster doesn't emit 'listening' event)
- Support reusePort in worker_threads mode (all workers share same port)
- Add test fixtures and tests for reusePort functionality

Synced from eggjs/cluster#115

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 30, 2025

📝 Walkthrough

Walkthrough

This pull request introduces reusePort support to egg-cluster, enabling the SO_REUSEPORT socket option for improved load balancing across multiple worker processes on supported platforms. Changes span configuration schemas, type definitions, worker implementation paths, and include new test fixtures demonstrating the feature.

Changes

Cohort / File(s) Summary
Configuration & Type Definitions
packages/egg/src/config/config.default.ts, packages/egg/src/lib/types.ts, packages/cluster/src/utils/options.ts
Added optional reusePort: boolean property (default false) to cluster.listen configuration across public configuration shape and ClusterOptions interface
Message Schema
packages/cluster/src/utils/messenger.ts
Extended MessageBody interface with optional reusePort?: boolean flag to propagate reusePort state through IPC messaging
App Worker Core
packages/cluster/src/app_worker.ts
Implements reusePort handling with platform detection (REUSE_PORT_SUPPORTED_PLATFORMS whitelist), conditional ListenOptions usage, enhanced debug logging at configuration and listen stages, and includes reusePort in app-start handshake payload
Process Mode Routing
packages/cluster/src/utils/mode/impl/process/app.ts
Adds debug logger and conditional routing: when app-start action includes reusePort=true, sends message via cluster.worker.send() instead of process.send() with explanatory comment about cluster listening behavior
Worker Threads Mode Forking
packages/cluster/src/utils/mode/impl/worker_threads/app.ts
Restructures fork() logic into two distinct paths: reusePort mode (forks same worker with identical options per fork) vs. non-reusePort mode (forks workers with individual port values)
Test Suite & Fixtures
packages/cluster/test/app_worker.test.ts, packages/cluster/test/fixtures/apps/app-listen-reusePort/...
Added Linux-specific test for reusePort behavior and non-Linux test verifying reusePort defaults to false; includes new fixture app with router returning port information and config enabling reusePort on port 17010

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 A port that's reused, oh what a sight!

Multiple workers dancing in the night,

Linux and platforms, all balanced with care,

Load-sharing magic floating through the air! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding reusePort support for server listen in the cluster module.
Linked Issues check ✅ Passed The PR successfully implements all primary objectives from issue #5728: adds reusePort option, validates platform support, handles message routing for reusePort, supports worker_threads mode, and includes comprehensive tests.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing reusePort support across cluster options, configuration, app workers, message handling, worker modes, and test fixtures.
✨ Finishing touches
  • 📝 Generate docstrings

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 and usage tips.

@fengmk2 fengmk2 marked this pull request as ready for review December 30, 2025 05:19
Copilot AI review requested due to automatic review settings December 30, 2025 05:19
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @fengmk2, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the clustering capabilities by integrating the SO_REUSEPORT socket option. This feature enables multiple worker processes to listen on the same network port, allowing the operating system to efficiently distribute incoming connections among them. The changes include adding configuration options, implementing platform-specific checks, adjusting server listening calls, and updating inter-process communication to ensure seamless operation in both process and worker_threads cluster modes. This improvement aims to provide better load balancing and resource utilization for applications deployed in clustered environments.

Highlights

  • SO_REUSEPORT Support: Introduced support for the SO_REUSEPORT socket option, allowing multiple server sockets to bind to the same port for improved load balancing in cluster scenarios.
  • Platform Validation: Added validation to ensure reusePort is only enabled on supported platforms (Linux 3.9+, DragonFlyBSD 3.6+, FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+), with automatic fallback to false on unsupported systems.
  • Server Listen Logic: Modified the server listening mechanism to use the server.listen({ port, reusePort, host }) options object when reusePort is enabled.
  • Cluster Message Handling: Updated message routing for cluster workers to correctly handle app-start events when reusePort is active, as the standard 'listening' event is not emitted in this configuration.
  • Worker Threads Integration: Ensured reusePort functionality is compatible with worker_threads mode, allowing all workers to share the same port when the option is enabled.
  • Configuration and Testing: Added a reusePort option to ClusterOptions and EggAppConfig, along with new test fixtures and comprehensive tests to verify the new functionality.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@cloudflare-workers-and-pages
Copy link

Deploying egg with  Cloudflare Pages  Cloudflare Pages

Latest commit: 7247684
Status: ✅  Deploy successful!
Preview URL: https://86e6b542.egg-cci.pages.dev
Branch Preview URL: https://reuse-port-pick.egg-cci.pages.dev

View logs

@codecov
Copy link

codecov bot commented Dec 30, 2025

Codecov Report

❌ Patch coverage is 5.88235% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.57%. Comparing base (715f67a) to head (7247684).
⚠️ Report is 1 commits behind head on next.

Files with missing lines Patch % Lines
.../cluster/src/utils/mode/impl/worker_threads/app.ts 0.00% 11 Missing and 1 partial ⚠️
...ackages/cluster/src/utils/mode/impl/process/app.ts 20.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             next    #5754      +/-   ##
==========================================
- Coverage   87.62%   87.57%   -0.05%     
==========================================
  Files         563      563              
  Lines       10931    10940       +9     
  Branches     1241     1242       +1     
==========================================
+ Hits         9578     9581       +3     
- Misses       1269     1275       +6     
  Partials       84       84              

☔ View full report in Codecov by Sentry.
📢 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.

@socket-security
Copy link

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​types/​mocha@​10.0.101001007780100

View full report

@cloudflare-workers-and-pages
Copy link

Deploying egg-v3 with  Cloudflare Pages  Cloudflare Pages

Latest commit: 7247684
Status: ✅  Deploy successful!
Preview URL: https://7ff48788.egg-v3.pages.dev
Branch Preview URL: https://reuse-port-pick.egg-v3.pages.dev

View logs

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for the SO_REUSEPORT socket option, which is a great feature for improving load balancing in clustered environments. The implementation is thorough, covering platform validation, handling differences between process and worker_threads modes, and updating messaging logic to accommodate the fact that the listening event isn't emitted when reusePort is active. The changes are well-documented and include comprehensive tests for both the new functionality and the fallback behavior on unsupported platforms. I have one suggestion to improve code readability in the worker forking logic.

Comment on lines +160 to +165
let i = 0;
do {
const options = Object.assign({}, this.options, { port: ports[i] });
const argv = [JSON.stringify(options)];
this.#forkSingle(this.getAppWorkerFile(), { argv }, ++i);
} while (i < ports.length);
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The do-while loop for forking workers in non-reusePort mode is a bit unconventional and less readable than a standard for loop. Refactoring this to use a for loop and modern object spread syntax would improve code clarity and maintainability, making it more consistent with the reusePort logic branch.

      for (let i = 0; i < ports.length; i++) {
        const options = { ...this.options, port: ports[i] };
        const argv = [JSON.stringify(options)];
        this.#forkSingle(this.getAppWorkerFile(), { argv }, i + 1);
      }

@fengmk2
Copy link
Member Author

fengmk2 commented Dec 30, 2025

Raw prompt

将 egg-cluster  的「support reusePort on server listen」功能同步到 @packages/cluster 
egg-cluster 源代码地址 ~/git/github.com/eggjs/cluster

---

Synchronize the "support reusePort on server listen" feature of egg-cluster to @packages/cluster.  
The source code address of egg-cluster is ~/git/github.com/eggjs/cluster.

**Review and understand the current implementation status with your subagent**, or your context will quickly become exhausted.
Then create a plan achieve this with your ultrathink

Copy link
Contributor

Copilot AI left a comment

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 adds SO_REUSEPORT socket option support to enable multiple server sockets to bind to the same port with OS-level load balancing in cluster scenarios.

  • Adds reusePort configuration option with platform validation (Linux, FreeBSD, Solaris, AIX)
  • Implements special message routing for cluster mode since Node.js cluster doesn't emit 'listening' event with reusePort
  • Supports both process and worker_threads cluster modes with appropriate handling for each

Reviewed changes

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

Show a summary per file
File Description
packages/egg/src/lib/types.ts Adds reusePort property to EggAppConfig cluster.listen interface with documentation
packages/egg/src/config/config.default.ts Sets default reusePort value to false in cluster configuration
packages/cluster/src/utils/options.ts Adds reusePort option to ClusterOptions interface with documentation
packages/cluster/src/utils/messenger.ts Adds reusePort flag to MessageBody to handle cluster event routing
packages/cluster/src/app_worker.ts Implements platform validation and server.listen() logic with reusePort support
packages/cluster/src/utils/mode/impl/process/app.ts Adds special message handling for reusePort in process mode (uses cluster.worker.send())
packages/cluster/src/utils/mode/impl/worker_threads/app.ts Implements worker forking logic for reusePort mode (all workers share same port)
packages/cluster/test/app_worker.test.ts Adds tests for reusePort functionality on Linux and fallback behavior on other platforms
packages/cluster/test/fixtures/apps/app-listen-reusePort/* Test fixture application with reusePort enabled in configuration

hostname: string;
/**
* enable SO_REUSEPORT socket option for server listen, default is `false`.
* Only available on Linux 3.9+, DragonFlyBSD 3.6+, FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+.
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

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

The comment mentions DragonFlyBSD 3.6+ as a supported platform, but this doesn't match the platform validation logic in app_worker.ts. The REUSE_PORT_SUPPORTED_PLATFORMS array doesn't include a DragonFlyBSD platform identifier. Either remove DragonFlyBSD from the documentation or ensure the implementation supports it.

Suggested change
* Only available on Linux 3.9+, DragonFlyBSD 3.6+, FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+.
* Only available on Linux 3.9+, FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+.

Copilot uses AI. Check for mistakes.
* @property {Number} listen.port - set a port when server listen
* @property {String} listen.hostname - set a hostname binding server when server listen
* @property {Boolean} listen.reusePort - enable SO_REUSEPORT socket option, default is `false`.
* Only available on Linux 3.9+, DragonFlyBSD 3.6+, FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+.
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

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

The comment mentions DragonFlyBSD 3.6+ as a supported platform, but this doesn't match the platform validation logic in app_worker.ts. The REUSE_PORT_SUPPORTED_PLATFORMS array doesn't include a DragonFlyBSD platform identifier. Either remove DragonFlyBSD from the documentation or ensure the implementation supports it.

Suggested change
* Only available on Linux 3.9+, DragonFlyBSD 3.6+, FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+.
* Only available on Linux 3.9+, FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+.

Copilot uses AI. Check for mistakes.
sticky?: boolean;
/**
* enable SO_REUSEPORT socket option for server listen, default is `false`.
* Only available on Linux 3.9+, DragonFlyBSD 3.6+, FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+.
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

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

The comment mentions DragonFlyBSD 3.6+ as a supported platform, but this doesn't match the platform validation logic in app_worker.ts. The REUSE_PORT_SUPPORTED_PLATFORMS array doesn't include a DragonFlyBSD platform identifier. Either remove DragonFlyBSD from the documentation or ensure the implementation supports it.

Suggested change
* Only available on Linux 3.9+, DragonFlyBSD 3.6+, FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+.
* Only available on Linux 3.9+, FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+.

Copilot uses AI. Check for mistakes.
// https://nodejs.org/api/net.html#serverlistenoptions-callback
// https://github.com/nodejs/node/blob/main/node.gypi#L310
// https://docs.python.org/3/library/sys.html#sys.platform
// This option is available only on some platforms, such as Linux 3.9+, DragonFlyBSD 3.6+, FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+.
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

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

The comment mentions DragonFlyBSD 3.6+ as a supported platform, but the REUSE_PORT_SUPPORTED_PLATFORMS array doesn't include 'dragonflybsd'. According to Node.js os.platform() documentation, DragonFlyBSD would likely return 'dragonfly' or similar, not 'freebsd'. Either update the comment to remove DragonFlyBSD from the list of supported platforms, or add the appropriate platform identifier to the array if DragonFlyBSD support is intended.

Suggested change
// This option is available only on some platforms, such as Linux 3.9+, DragonFlyBSD 3.6+, FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+.
// This option is available only on some platforms, such as Linux 3.9+, FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
packages/cluster/test/app_worker.test.ts (1)

289-311: Good test coverage for reusePort feature.

The tests appropriately verify:

  • Linux-specific behavior with multiple workers (the primary reusePort use case)
  • Graceful fallback on non-Linux platforms
  • Basic HTTP functionality after enabling reusePort

However, based on learnings about features affecting HTTP or process orchestration, consider adding a TypeScript fixture variant to complement the existing CommonJS test app.

Optional: Add verification that reusePort actually affects listen behavior

You might want to add assertions that verify the reusePort flag is actually applied. For example, check the debug logs or stdout to confirm the platform validation logic ran and that the correct listen path was taken:

  it.skipIf(process.platform !== 'linux')('should use reusePort in config on Linux', async () => {
    app = cluster('apps/app-listen-reusePort', { port: 0, workers: 2 });
    // app.debug();
    await app.ready();

    app.expect('code', 0);
    app.expect('stdout', /egg started on http:\/\/127.0.0.1:17010/);
+   app.expect('stdout', /listen with reusePort options/);

    await request('http://127.0.0.1:17010').get('/').expect('done').expect(200);
    await request('http://127.0.0.1:17010').get('/port').expect('17010').expect(200);
  });
packages/cluster/src/app_worker.ts (1)

182-198: LGTM! Listen logic correctly handles reusePort.

The implementation appropriately uses:

  • Options object form when reusePort is enabled (required by Node.js API)
  • Traditional variadic arguments for backward compatibility when reusePort is disabled

The hostname → host mapping is correct per the ListenOptions interface.

Optional: Make non-reusePort path more type-safe

The variadic spread with args array works, but could be more explicit for better type safety:

        } else {
-         const args = [port];
+         const args: [number, string?] = [port];
          if (listenConfig.hostname) {
            args.push(listenConfig.hostname);
          }
          debug('listen options %j', args);
          server.listen(...args);
        }

Or even more explicitly:

        } else {
-         const args = [port];
-         if (listenConfig.hostname) {
-           args.push(listenConfig.hostname);
-         }
-         debug('listen options %j', args);
-         server.listen(...args);
+         if (listenConfig.hostname) {
+           debug('listen options %j', [port, listenConfig.hostname]);
+           server.listen(port, listenConfig.hostname);
+         } else {
+           debug('listen options %j', [port]);
+           server.listen(port);
+         }
        }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 715f67a and 7247684.

📒 Files selected for processing (12)
  • packages/cluster/src/app_worker.ts
  • packages/cluster/src/utils/messenger.ts
  • packages/cluster/src/utils/mode/impl/process/app.ts
  • packages/cluster/src/utils/mode/impl/worker_threads/app.ts
  • packages/cluster/src/utils/options.ts
  • packages/cluster/test/app_worker.test.ts
  • packages/cluster/test/fixtures/apps/app-listen-reusePort/app.js
  • packages/cluster/test/fixtures/apps/app-listen-reusePort/app/router.js
  • packages/cluster/test/fixtures/apps/app-listen-reusePort/config/config.default.js
  • packages/cluster/test/fixtures/apps/app-listen-reusePort/package.json
  • packages/egg/src/config/config.default.ts
  • packages/egg/src/lib/types.ts
🧰 Additional context used
📓 Path-based instructions (10)
packages/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

packages/**/*.ts: Use TypeScript throughout all packages in the Eggjs monorepo
Use strict TypeScript mode in all packages

Files:

  • packages/cluster/src/utils/mode/impl/worker_threads/app.ts
  • packages/cluster/src/utils/options.ts
  • packages/cluster/test/app_worker.test.ts
  • packages/egg/src/lib/types.ts
  • packages/cluster/src/utils/mode/impl/process/app.ts
  • packages/egg/src/config/config.default.ts
  • packages/cluster/src/utils/messenger.ts
  • packages/cluster/src/app_worker.ts
**/*.{ts,tsx,js,mjs}

📄 CodeRabbit inference engine (AGENTS.md)

Use .ts sources over CommonJS and prefer ESM for exports

Use ESM (ES Modules) syntax with 'import' and 'export' statements - add 'type: module' to package.json for CommonJS to ESM migration

Files:

  • packages/cluster/src/utils/mode/impl/worker_threads/app.ts
  • packages/cluster/test/fixtures/apps/app-listen-reusePort/config/config.default.js
  • packages/cluster/test/fixtures/apps/app-listen-reusePort/app.js
  • packages/cluster/src/utils/options.ts
  • packages/cluster/test/app_worker.test.ts
  • packages/egg/src/lib/types.ts
  • packages/cluster/src/utils/mode/impl/process/app.ts
  • packages/egg/src/config/config.default.ts
  • packages/cluster/src/utils/messenger.ts
  • packages/cluster/test/fixtures/apps/app-listen-reusePort/app/router.js
  • packages/cluster/src/app_worker.ts
{packages,plugins}/**/*.{ts,tsx,js,mjs}

📄 CodeRabbit inference engine (AGENTS.md)

Name files in lowercase with hyphens (e.g. loader-context.ts)

Files:

  • packages/cluster/src/utils/mode/impl/worker_threads/app.ts
  • packages/cluster/test/fixtures/apps/app-listen-reusePort/config/config.default.js
  • packages/cluster/test/fixtures/apps/app-listen-reusePort/app.js
  • packages/cluster/src/utils/options.ts
  • packages/cluster/test/app_worker.test.ts
  • packages/egg/src/lib/types.ts
  • packages/cluster/src/utils/mode/impl/process/app.ts
  • packages/egg/src/config/config.default.ts
  • packages/cluster/src/utils/messenger.ts
  • packages/cluster/test/fixtures/apps/app-listen-reusePort/app/router.js
  • packages/cluster/src/app_worker.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Name classes in PascalCase
Name functions and variables in camelCase

Files:

  • packages/cluster/src/utils/mode/impl/worker_threads/app.ts
  • packages/cluster/src/utils/options.ts
  • packages/cluster/test/app_worker.test.ts
  • packages/egg/src/lib/types.ts
  • packages/cluster/src/utils/mode/impl/process/app.ts
  • packages/egg/src/config/config.default.ts
  • packages/cluster/src/utils/messenger.ts
  • packages/cluster/src/app_worker.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: All exported functions and methods must have explicit return type annotations to support TypeScript's isolatedDeclarations flag
Avoid using computed property names with symbols in class declarations - use override methods instead for custom property definitions
Use explicit type annotations for class properties and add 'unique symbol' type for exported symbols to support isolatedDeclarations
Enable strict mode in all TypeScript packages and use explicit return types for public APIs
Prefer interfaces over type aliases for object shapes in TypeScript
Use readonly modifiers where appropriate in TypeScript class properties and interface definitions
Avoid using 'any' type in TypeScript - use 'unknown' when type is truly unknown
Use BaseContextClass as the base class for context-aware components like services and subscriptions in Egg applications
Monitor memory usage and implement proper cleanup in lifecycle hooks to avoid memory leaks in long-running processes
Avoid global state in worker processes - use application context or request context for state management

Files:

  • packages/cluster/src/utils/mode/impl/worker_threads/app.ts
  • packages/cluster/src/utils/options.ts
  • packages/cluster/test/app_worker.test.ts
  • packages/egg/src/lib/types.ts
  • packages/cluster/src/utils/mode/impl/process/app.ts
  • packages/egg/src/config/config.default.ts
  • packages/cluster/src/utils/messenger.ts
  • packages/cluster/src/app_worker.ts
**/test/fixtures/**

📄 CodeRabbit inference engine (AGENTS.md)

Place reusable test data under test/fixtures/

Files:

  • packages/cluster/test/fixtures/apps/app-listen-reusePort/config/config.default.js
  • packages/cluster/test/fixtures/apps/app-listen-reusePort/app.js
  • packages/cluster/test/fixtures/apps/app-listen-reusePort/app/router.js
  • packages/cluster/test/fixtures/apps/app-listen-reusePort/package.json
packages/**/test/**/*.test.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

packages/**/test/**/*.test.ts: Use Vitest as the standard test runner for all packages; test files follow pattern 'test/**/*.test.ts'
Use 'import { describe, it } from "vitest"' for test functions in Vitest test files
Use Node.js built-in 'assert' module for assertions in tests

Files:

  • packages/cluster/test/app_worker.test.ts
**/test/**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

Configure Vitest to discover **/test/**/*.test.ts within each package and mirror this pattern when adding test suites

**/test/**/*.test.ts: Test files in Vitest-based packages must follow the naming pattern 'test/**/*.test.ts' and import test functions from vitest
Configure test files to use Node.js built-in 'assert' module for assertions in Vitest tests
Import test functions (describe, it, expect, beforeEach, afterEach) from 'vitest' package in test files

Files:

  • packages/cluster/test/app_worker.test.ts
packages/egg/src/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Work primarily in 'packages/egg/src/' for core framework features, organizing into lib/, app/extend/, config/, and lib/loader/ directories

Files:

  • packages/egg/src/lib/types.ts
  • packages/egg/src/config/config.default.ts
**/package.json

📄 CodeRabbit inference engine (CLAUDE.md)

**/package.json: Use 'workspace:*' for internal package dependencies in package.json to ensure workspace linking
Use 'catalog:' prefix for external dependencies defined in pnpm-workspace.yaml catalog in package.json files
Add 'type: module' to package.json to enable ES Module support and convert from CommonJS to ESM

Files:

  • packages/cluster/test/fixtures/apps/app-listen-reusePort/package.json
🧠 Learnings (10)
📚 Learning: 2025-12-21T14:11:29.307Z
Learnt from: CR
Repo: eggjs/egg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T14:11:29.307Z
Learning: Applies to **/*.ts : Avoid global state in worker processes - use application context or request context for state management

Applied to files:

  • packages/cluster/src/utils/mode/impl/worker_threads/app.ts
  • packages/cluster/src/utils/mode/impl/process/app.ts
  • packages/cluster/src/app_worker.ts
📚 Learning: 2025-12-20T09:24:59.960Z
Learnt from: CR
Repo: eggjs/egg PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-20T09:24:59.960Z
Learning: Add regression cases that exercise both CommonJS and TypeScript example apps when features affect HTTP or process orchestration

Applied to files:

  • packages/cluster/src/utils/mode/impl/worker_threads/app.ts
  • packages/cluster/test/fixtures/apps/app-listen-reusePort/config/config.default.js
  • packages/cluster/test/fixtures/apps/app-listen-reusePort/app.js
  • packages/cluster/test/app_worker.test.ts
  • packages/cluster/src/utils/mode/impl/process/app.ts
  • packages/cluster/test/fixtures/apps/app-listen-reusePort/app/router.js
  • packages/cluster/src/app_worker.ts
📚 Learning: 2025-12-21T03:05:13.313Z
Learnt from: CR
Repo: eggjs/egg PR: 0
File: tegg/CLAUDE.md:0-0
Timestamp: 2025-12-21T03:05:13.313Z
Learning: Applies to tegg/**/__tests__/**/*.test.{ts,tsx} : Use `MockApplication` from `eggjs/mock` for testing with `mockModuleContextScope()` to create context scope

Applied to files:

  • packages/cluster/test/fixtures/apps/app-listen-reusePort/app.js
📚 Learning: 2025-11-27T14:37:59.711Z
Learnt from: CR
Repo: eggjs/egg PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T14:37:59.711Z
Learning: Applies to packages/**/*.ts : Use TypeScript throughout all packages in the Eggjs monorepo

Applied to files:

  • packages/egg/src/lib/types.ts
📚 Learning: 2025-12-21T14:11:29.307Z
Learnt from: CR
Repo: eggjs/egg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T14:11:29.307Z
Learning: Applies to plugins/*/src/types.ts : All Egg framework plugins MUST define a 'src/types.ts' file that extends the Egg module declarations using 'declare module "egg"' and defines typed configuration

Applied to files:

  • packages/egg/src/lib/types.ts
📚 Learning: 2025-12-21T03:05:13.313Z
Learnt from: CR
Repo: eggjs/egg PR: 0
File: tegg/CLAUDE.md:0-0
Timestamp: 2025-12-21T03:05:13.313Z
Learning: Applies to tegg/core/*/tsconfig.json : Each new core package should include `tsconfig.json` extending `eggjs/tsconfig`

Applied to files:

  • packages/egg/src/lib/types.ts
  • packages/egg/src/config/config.default.ts
📚 Learning: 2025-12-21T14:11:29.307Z
Learnt from: CR
Repo: eggjs/egg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T14:11:29.307Z
Learning: Applies to packages/egg/src/lib/start.ts : Implement graceful shutdown in application startup to support zero-downtime deployments

Applied to files:

  • packages/cluster/src/utils/mode/impl/process/app.ts
  • packages/cluster/src/app_worker.ts
📚 Learning: 2025-12-21T14:11:29.307Z
Learnt from: CR
Repo: eggjs/egg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T14:11:29.307Z
Learning: Applies to **/src/agent.ts : Use agent process for background tasks and heavy computations to avoid blocking worker processes

Applied to files:

  • packages/cluster/src/utils/mode/impl/process/app.ts
📚 Learning: 2025-12-21T14:11:29.307Z
Learnt from: CR
Repo: eggjs/egg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T14:11:29.307Z
Learning: Applies to plugins/*/src/app.ts : App-specific plugin files (src/app.ts) must export a default function that runs in worker processes

Applied to files:

  • packages/cluster/src/utils/mode/impl/process/app.ts
📚 Learning: 2025-12-21T14:11:29.307Z
Learnt from: CR
Repo: eggjs/egg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-21T14:11:29.307Z
Learning: Applies to plugins/*/src/config/config.default.ts : Plugin configurations should be defined in config/config.default.ts following the Egg plugin configuration pattern with proper TypeScript typing

Applied to files:

  • packages/egg/src/config/config.default.ts
🧬 Code graph analysis (3)
packages/cluster/src/utils/mode/impl/worker_threads/app.ts (1)
packages/cluster/src/master.ts (1)
  • options (58-205)
packages/cluster/test/app_worker.test.ts (2)
packages/egg/test/utils.ts (2)
  • app (31-36)
  • cluster (47-50)
packages/cluster/test/utils.ts (1)
  • cluster (5-17)
packages/egg/src/config/config.default.ts (1)
packages/core/src/loader/egg_loader.ts (1)
  • config (1027-1031)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: Agent
  • GitHub Check: Test (windows-latest, 24, 3/3)
  • GitHub Check: Test (windows-latest, 20, 3/3)
  • GitHub Check: Test (windows-latest, 24, 1/3)
  • GitHub Check: Test (macos-latest, 22, 1/3)
  • GitHub Check: Test (windows-latest, 22, 1/3)
  • GitHub Check: Test (windows-latest, 22, 2/3)
  • GitHub Check: Test (windows-latest, 24, 2/3)
  • GitHub Check: Test (windows-latest, 20, 1/3)
  • GitHub Check: Test (windows-latest, 20, 2/3)
  • GitHub Check: Test (ubuntu-latest, 24, 3/3)
  • GitHub Check: Test (windows-latest, 22, 3/3)
  • GitHub Check: Test bin (windows-latest, 24, 2/3)
  • GitHub Check: Test bin (ubuntu-latest, 24, 1/3)
  • GitHub Check: Test bin (ubuntu-latest, 24, 0/3)
  • GitHub Check: Test bin (windows-latest, 24, 1/3)
  • GitHub Check: Test bin (windows-latest, 24, 0/3)
  • GitHub Check: typecheck
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Cloudflare Pages: egg-v3
🔇 Additional comments (11)
packages/cluster/test/fixtures/apps/app-listen-reusePort/package.json (1)

1-3: LGTM!

The fixture manifest is minimal and appropriate for test purposes, with the package name following the lowercase-with-hyphens convention.

packages/cluster/src/utils/mode/impl/worker_threads/app.ts (1)

143-152: LGTM! ReusePort mode implementation is correct.

The reusePort path properly validates that options.port is specified before forking workers, and correctly passes identical options to all workers so they can share the same port.

packages/cluster/test/fixtures/apps/app-listen-reusePort/app.js (1)

1-4: LGTM! Test fixture setup is appropriate.

The fixture correctly disables the egg-mock default port by setting app._options.port to undefined, allowing the reusePort configuration to be tested. Accessing private fields is acceptable in test fixtures.

packages/cluster/src/utils/options.ts (1)

81-86: LGTM! Well-documented platform-specific option.

The reusePort option is properly documented with clear platform requirements and links to Node.js documentation. The JSDoc explicitly notes the supported platforms (Linux 3.9+, DragonFlyBSD 3.6+, FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+), which helps developers understand when this feature can be used.

packages/egg/src/lib/types.ts (1)

261-266: LGTM! Type definition aligns with cluster options.

The reusePort property is correctly added to EggAppConfig.cluster.listen with documentation that matches the ClusterOptions interface. This ensures type consistency across the configuration surface.

packages/egg/src/config/config.default.ts (1)

362-370: LGTM! Safe default configuration.

The reusePort option is set to false by default, making this an opt-in feature. This is a safe choice since SO_REUSEPORT is platform-specific and requires explicit configuration. The documentation is consistent with the type definition.

packages/cluster/src/utils/messenger.ts (1)

22-27: LGTM! Clear documentation of message flag.

The reusePort flag is added to the MessageBody interface with excellent documentation explaining why it's needed: when reusePort is true, cluster won't emit the listening event, so the message event must be used instead. This contextual information helps maintainers understand the behavior change.

packages/cluster/test/fixtures/apps/app-listen-reusePort/app/router.js (1)

1-9: LGTM! Test router supports reusePort validation.

The router provides endpoints for testing the reusePort functionality:

  • GET / for basic health checks
  • GET /port to verify the port configuration is correctly passed to workers

This is a standard pattern for test fixtures in Egg applications.

packages/cluster/test/fixtures/apps/app-listen-reusePort/config/config.default.js (1)

1-9: LGTM! Test fixture appropriately uses CommonJS.

The configuration correctly enables reusePort for testing purposes. The use of CommonJS (module.exports) aligns with the learning about testing both CommonJS and TypeScript example apps for features affecting HTTP or process orchestration.

packages/cluster/src/app_worker.ts (1)

101-110: LGTM! Platform validation with graceful fallback.

The implementation correctly:

  • Validates platform support for SO_REUSEPORT
  • Falls back to false on unsupported platforms without throwing errors
  • Logs the fallback for debugging purposes

This ensures the feature degrades gracefully rather than failing on unsupported platforms.

packages/cluster/src/utils/mode/impl/process/app.ts (1)

51-57: Non-null assertion on cluster.worker is safe and correct.

The static send() method is only called from app_worker.ts, which executes exclusively in worker processes spawned by cfork. In Node.js cluster worker processes, cluster.worker is always defined. The master process uses instance methods (this.messenger.send() and worker.instance.send()) and never calls the static method. The non-null assertion accurately reflects the guaranteed execution context.

Likely an incorrect or invalid review comment.

Comment on lines +17 to +21
// https://nodejs.org/api/net.html#serverlistenoptions-callback
// https://github.com/nodejs/node/blob/main/node.gypi#L310
// https://docs.python.org/3/library/sys.html#sys.platform
// This option is available only on some platforms, such as Linux 3.9+, DragonFlyBSD 3.6+, FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+.
const REUSE_PORT_SUPPORTED_PLATFORMS = ['linux', 'freebsd', 'sunos', 'aix'];
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n packages/cluster/src/app_worker.ts | head -30

Repository: eggjs/egg

Length of output: 1560


🌐 Web query:

Node.js SO_REUSEPORT platform support documentation server.listen() supported platforms

💡 Result:

Node.js supports the server.listen({ reusePort: true }) option only on some OSes — specifically: Linux (kernel ≥ 3.9), DragonFlyBSD (≥ 3.6), FreeBSD (≥ 12.0), Solaris 11.4, and AIX 7.2.5+. The reusePort option was added in Node v22.12.0 / v23.1.0. Windows is not listed as supported. [1][2]

Sources:

  • Node.js server.listen docs (reusePort supported platforms + history). [1]
  • Node.js server.listen (v25 API page showing reusePort text & history). [2]

🏁 Script executed:

# Check for usages of REUSE_PORT_SUPPORTED_PLATFORMS
rg "REUSE_PORT_SUPPORTED_PLATFORMS" packages/cluster/src/

Repository: eggjs/egg

Length of output: 279


🌐 Web query:

Node.js os.platform() return value for DragonFlyBSD

💡 Result:

Node.js does not return "dragonfly". os.platform() / process.platform only return one of: 'aix', 'darwin', 'freebsd', 'linux', 'openbsd', 'sunos', 'win32' (and sometimes 'android'). DragonFly BSD is not listed as a distinct value. [1]

Sources:

  • Node.js os.platform() / process.platform documentation. [1]

Remove DragonFlyBSD reference from comment or add 'dragonfly' to supported platforms array.

The comment mentions "DragonFlyBSD 3.6+" as a supported platform where SO_REUSEPORT is available, but the REUSE_PORT_SUPPORTED_PLATFORMS array doesn't include any value for it. Since os.platform() returns 'freebsd' for FreeBSD but does not return 'dragonfly' for DragonFlyBSD (DragonFlyBSD is not a documented return value from os.platform()), DragonFlyBSD systems cannot be detected by the current check, making the comment inaccurate.

Either remove the DragonFlyBSD reference from the comment since it cannot be detected, or verify if there's an alternative detection mechanism for DragonFlyBSD systems.

🤖 Prompt for AI Agents
In packages/cluster/src/app_worker.ts around lines 17 to 21, the comment
references "DragonFlyBSD" but the REUSE_PORT_SUPPORTED_PLATFORMS array does not
include a matching platform string and os.platform() does not reliably return a
DragonFlyBSD identifier; update the file by either removing the DragonFlyBSD
mention from the comment to keep it accurate, or if you want to support
DragonFlyBSD, add the correct platform string (confirm the exact os.platform()
value for DragonFlyBSD) to REUSE_PORT_SUPPORTED_PLATFORMS and add a unit/test or
runtime check to ensure detection works cross-platform.

Comment on lines +153 to +165
} else {
// Normal mode: each worker can have a different port
const ports = this.options.ports ?? [];
if (!ports.length) {
ports.push(this.options.port!);
}
this.options.workers = ports.length;
let i = 0;
do {
const options = Object.assign({}, this.options, { port: ports[i] });
const argv = [JSON.stringify(options)];
this.#forkSingle(this.getAppWorkerFile(), { argv }, ++i);
} while (i < ports.length);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's check the target file and surrounding context
echo "=== Checking target file: packages/cluster/src/utils/mode/impl/worker_threads/app.ts ==="
if [ -f "packages/cluster/src/utils/mode/impl/worker_threads/app.ts" ]; then
  wc -l packages/cluster/src/utils/mode/impl/worker_threads/app.ts
  echo "--- Lines 150-170 for context ---"
  sed -n '150,170p' packages/cluster/src/utils/mode/impl/worker_threads/app.ts
else
  echo "File not found, searching for it..."
  find . -name "app.ts" -path "*/worker_threads/*" 2>/dev/null
fi

Repository: eggjs/egg

Length of output: 886


🏁 Script executed:

#!/bin/bash
# Search for parseOptions function and how port is handled
echo "=== Searching for parseOptions function ==="
rg -n "parseOptions" --type=ts | head -20

Repository: eggjs/egg

Length of output: 1859


🏁 Script executed:

#!/bin/bash
# Look for port initialization in Master class
echo "=== Checking Master class for port initialization ==="
rg -n "this.options.port" packages/cluster/src/ --type=ts -A 2 -B 2 | head -50

Repository: eggjs/egg

Length of output: 1727


🏁 Script executed:

#!/bin/bash
# Search for tests related to worker_threads mode
echo "=== Checking tests with worker_threads ==="
fd -e test.ts -e spec.ts packages/cluster | head -10

Repository: eggjs/egg

Length of output: 482


🏁 Script executed:

#!/bin/bash
# Check the parseOptions implementation
echo "=== Checking parseOptions implementation ==="
sed -n '100,200p' packages/cluster/src/utils/options.ts

Repository: eggjs/egg

Length of output: 2754


🏁 Script executed:

#!/bin/bash
# Check the ParsedClusterOptions type definition
echo "=== Checking type definitions ==="
rg -n "interface ParsedClusterOptions|type ParsedClusterOptions" --type=ts -A 20 packages/cluster/src/utils/

Repository: eggjs/egg

Length of output: 1542


🏁 Script executed:

#!/bin/bash
# Look at test cases for parseOptions
echo "=== Checking parseOptions tests ==="
cat packages/cluster/test/options.test.ts

Repository: eggjs/egg

Length of output: 8577


Add a guard to ensure options.port is defined in normal mode, or use a fallback port.

The code assumes options.port is defined at line 157, but parseOptions explicitly defaults it to undefined unless HTTPS is enabled (see packages/cluster/src/utils/options.ts:103). Test cases confirm port can be undefined by default. This is inconsistent with reusePort mode, which validates port with an explicit error at lines 146-148. If port is undefined, the ports array receives undefined, and workers get port: undefined in their options, which will cause issues.

Either add a check like reusePort mode does, or provide a sensible default port (e.g., 7001).

🤖 Prompt for AI Agents
In packages/cluster/src/utils/mode/impl/worker_threads/app.ts around lines 153
to 165, the code can push an undefined port into the ports array when
this.options.port is undefined; update the block so that when ports is empty it
uses a validated port value (either throw a clear error like the reusePort
branch or set a sensible fallback, e.g., const defaultPort = 7001) and push that
instead of undefined, ensure the pushed value is a defined number before
assigning this.options.workers and forking workers so each worker receives a
concrete port in its options.

@fengmk2 fengmk2 merged commit 19db506 into next Dec 30, 2025
53 of 57 checks passed
@fengmk2 fengmk2 deleted the reuse-port-pick branch December 30, 2025 05:37
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.

egg-cluster support reusePort

2 participants