Skip to content

Conversation

@fengmk2
Copy link
Member

@fengmk2 fengmk2 commented Oct 26, 2024

closes eggjs/egg#5365

Summary by CodeRabbit

  • New Features

    • Added reusePort support to allow multiple sockets to listen on the same port where supported.
  • Improvements

    • Improved agent startup error handling and clearer debug logs.
    • CI now tests Node.js 24; package metadata and project links updated; version bumped.
  • Tests

    • Added unit/integration and cluster tests exercising reusePort and related startup flows.
  • Documentation

    • README updated with reusePort details.
  • Other

    • .gitignore updated.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 26, 2024

Warning

Rate limit exceeded

@fengmk2 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 0 minutes and 0 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 144b559 and 9e99e6f.

📒 Files selected for processing (5)
  • lib/app_worker.js (3 hunks)
  • lib/utils/mode/impl/process/app.js (2 hunks)
  • package.json (2 hunks)
  • test/app_worker.test.js (1 hunks)
  • test/master.test.js (1 hunks)

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Add a public reusePort option (default false), wire platform-aware reusePort handling into master, app-worker, and worker_threads forking/listening, add tests and a clustered reuseport script, update CI/packaging metadata and README, and refine agent/app-worker logging and startup error handling.

Changes

Cohort / File(s) Summary
CI & package metadata
\.github/workflows/nodejs.yml, package.json, \.gitignore
Add Node 24 to CI matrix; bump package to 2.5.0-beta.3; update repository/bugs/homepage URLs to cluster; run test/reuseport_cluster.js in CI; add pnpm-lock.yaml to .gitignore; adjust cov/ci scripts and NODE_DEBUG usage.
Public option & docs
lib/utils/options.js, lib/master.js, README.md
Add reusePort default false to options and JSDoc for Master constructor; document reusePort and clarify ports/startMode in README; update codecov badges/links.
App worker: listen & messaging
lib/app_worker.js, lib/utils/mode/impl/process/app.js
Extract reusePort from options/listen config; disable on unsupported platforms with debug log; when enabled use server.listen({ port, reusePort, host? }) and log listenOptions; include reusePort in AppWorker send payload; route reuse-port listening via cluster messaging and handle reuse-port-listening messages to create app-start.
worker_threads mode: forking & lifecycle
lib/utils/mode/impl/worker_threads/app.js
Replace internal worker collection with #appWorkers; add reusePort-aware forking: if reusePort=true fork N identical workers (distinct appWorkerId/argv), otherwise preserve per-port forking; update exit/refork/kill logic and disableRefork guards; improve listener cleanup and error handling on exit.
Agent worker: startup/error handling & logging
lib/agent_worker.js
Change debug namespace to egg-cluster:agent_worker; add startErrorHandler to log and exit on initialization errors and avoid sending start to master on failure.
Tests & fixtures
test/reuseport_cluster.js, test/app_worker.test.js, test/master.test.js, test/fixtures/apps/app-listen-reusePort/*
Add clustered reusePort test script; add focused app_worker and master tests for reusePort (including an only test in app_worker.test.js); add fixture app-listen-reusePort with config (port 17010, reusePort: true), router, app.js (unset port) and package.json.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Master
    participant Options
    participant Forker as Forker/ModeImpl
    participant AppWorker
    participant Kernel as OS/Kernel
    Note over Master,Options: Start cluster with reusePort config

    Master->>Options: read cluster config (includes reusePort)
    Options->>Options: normalize + platform support check
    alt platform unsupported
        Options-->>Master: reusePort = false (override)
    else platform supports reusePort
        Options-->>Master: reusePort = true/false (as configured)
    end

    Master->>Forker: start forking (process or worker_threads)
    alt reusePort = true
        Forker->>AppWorker: fork N workers (same port, distinct appWorkerId/argv)
    else reusePort = false
        Forker->>AppWorker: fork per-port workers (existing behavior)
    end

    AppWorker->>Kernel: server.listen({ port, reusePort: <bool>, host? })
    Kernel-->>AppWorker: socket bound (SO_REUSEPORT applied if true)
    AppWorker-->>Master: send listening/start message (via cluster IPC when reusePort)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus areas:
    • lib/utils/mode/impl/worker_threads/app.js — forking counts, argv/appWorkerId assignment, refork/kill semantics, concurrency and cross-platform behavior.
    • lib/app_worker.js & lib/utils/mode/impl/process/app.js — server.listen branching, cluster vs process IPC, and message format (listening vs reuse-port-listening).
    • test/reuseport_cluster.js and CI integration — timing, flakiness, and reliability across platforms/CI runners.
    • agent_worker.js — ensure startup error handling doesn't suppress legitimate signals.

Poem

🐰 I nudged the kernel, whispered "share this gate",
Many paws answered, each one found its crate,
Linux hummed softly as SO_REUSEPORT played,
Logs blinked like lanterns where the handlers stayed,
One meadow, many doors — the rabbit danced, elate.

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 directly summarizes the main change - adding reusePort support to server listening.
Linked Issues check ✅ Passed All changes fully implement the linked objective: adding reusePort option to enable SO_REUSEPORT support for multiple workers binding to the same port.
Out of Scope Changes check ✅ Passed Changes include reusePort feature implementation, necessary Node.js workflow version bump, repository URL updates, and test infrastructure - all related to the primary objective.

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.

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: 4

🧹 Outside diff range and nitpick comments (7)
test/fixtures/apps/app-listen-reusePort/app/router.js (1)

6-8: Consider adding a comment about private API usage.

While accessing _options is acceptable in test fixtures, it would be helpful to add a comment explaining why we're accessing this private API to prevent confusion for other developers.

 app.get('/port', ctx => {
+  // Note: Accessing private _options API for testing reusePort functionality
   ctx.body = ctx.app._options.port;
 });
lib/utils/options.js (1)

15-15: LGTM with suggestions for improvement.

The reusePort option is correctly implemented with a safe default value of false. However, consider these improvements:

  1. Add JSDoc comments explaining the purpose and security implications of this option
  2. Add validation similar to other critical options

Apply this diff to add documentation and validation:

     port: options.https ? 8443 : null,
+    // Enable SO_REUSEPORT socket option for better performance with multiple workers.
+    // Warning: This allows multiple processes to bind to the same port.
+    // See: https://lwn.net/Articles/542629/
     reusePort: false,
     workers: null,

And add this validation after the port parsing:

   options.port = parseInt(options.port, 10) || undefined;
   options.workers = parseInt(options.workers, 10);
+  assert(typeof options.reusePort === 'boolean', 'options.reusePort must be a boolean');
   if (options.require) options.require = [].concat(options.require);
lib/app_worker.js (1)

130-130: Maintain consistent debug message format.

The debug messages use different string formats for the options:

  • debug('listen options %s', listenOptions) uses an object
  • debug('listen options %s', args) uses an array

Consider using the same format for consistency:

-debug('listen options %s', args);
+debug('listen options %j', { port, hostname: listenConfig.hostname });

Also applies to: 137-137

test/app_worker.test.js (1)

235-262: LGTM with suggestions for enhanced reusePort testing.

The test case follows the established pattern and verifies basic functionality. However, consider enhancing the test to specifically validate the reusePort behavior.

Consider adding these specific test scenarios:

// Verify reusePort is actually set
await request('http://127.0.0.1:17010')
  .get('/reusePort')
  .expect('true')
  .expect(200);

// Test multiple workers can bind to same port
const responses = await Promise.all([
  request('http://127.0.0.1:17010').get('/pid'),
  request('http://127.0.0.1:17010').get('/pid'),
]);
assert(responses[0].text !== responses[1].text, 'Requests should be handled by different workers');

This would require adding corresponding endpoints in your test app to expose:

  1. The reusePort setting status
  2. The worker process ID handling each request
lib/master.js (2)

37-37: Enhance documentation with performance and security notes.

While the documentation is comprehensive regarding platform compatibility, consider adding:

  1. Performance implications of using reusePort
  2. Security considerations, especially in multi-tenant environments
-   *  - {Boolean} [reusePort] setting `reusePort` to `true` allows multiple sockets on the same host to bind to the same port. Incoming connections are distributed by the operating system to listening sockets. 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+. **Default:** `false`.
+   *  - {Boolean} [reusePort] setting `reusePort` to `true` allows multiple sockets on the same host to bind to the same port. Incoming connections are distributed by the operating system to listening sockets, which can improve performance under high connection loads. 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+. Note: In multi-tenant environments, ensure proper isolation as all workers can bind to the same port. **Default:** `false`.

Line range hint 447-467: Add platform compatibility check for reusePort.

The code should verify platform support for SO_REUSEPORT at runtime to prevent startup failures on unsupported platforms.

Here's a suggested implementation:

 startMasterSocketServer(cb) {
+  // Check platform support for reusePort
+  if (this.options.reusePort) {
+    const isSupported = process.versions.node.split('.')[0] >= 12 &&
+      ['linux', 'freebsd', 'darwin'].includes(process.platform);
+    if (!isSupported) {
+      this.logger.warn(
+        '[master] reusePort is not supported on this platform. Falling back to default behavior.'
+      );
+      this.options.reusePort = false;
+    }
+  }
+
   // Create the outside facing server listening on our port.
   require('net').createServer({
     pauseOnConnect: true,
+    reusePort: this.options.reusePort,
   }, connection => {
test/master.test.js (1)

32-41: LGTM with suggestions for additional test coverage.

The test case correctly verifies the basic startup scenario with reusePort=true. However, consider adding more test cases to ensure comprehensive coverage:

  1. Verify that multiple workers can actually bind to the same port
  2. Test error scenarios (e.g., when port is already in use)
  3. Test port reuse across worker restarts

Here's a suggested additional test case:

it('should allow multiple workers to bind to same port with reusePort=true', async () => {
  app = utils.cluster('apps/master-worker-started', { 
    workers: 4,
    reusePort: true 
  });

  await app.expect('stdout', /egg start/)
    .expect('stdout', /egg started/)
    .expect('code', 0)
    .end();

  // Verify each worker bound successfully
  for (let i = 1; i <= 4; i++) {
    app.expect('stdout', new RegExp(`worker#${i}.*port bound successfully`));
  }
});
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between d892960 and 3d8d116.

📒 Files selected for processing (12)
  • .github/PULL_REQUEST_TEMPLATE.md (0 hunks)
  • .github/workflows/nodejs.yml (1 hunks)
  • README.md (1 hunks)
  • lib/app_worker.js (2 hunks)
  • lib/master.js (1 hunks)
  • lib/utils/options.js (1 hunks)
  • test/app_worker.test.js (1 hunks)
  • test/fixtures/apps/app-listen-reusePort/app.js (1 hunks)
  • test/fixtures/apps/app-listen-reusePort/app/router.js (1 hunks)
  • test/fixtures/apps/app-listen-reusePort/config/config.default.js (1 hunks)
  • test/fixtures/apps/app-listen-reusePort/package.json (1 hunks)
  • test/master.test.js (1 hunks)
💤 Files with no reviewable changes (1)
  • .github/PULL_REQUEST_TEMPLATE.md
✅ Files skipped from review due to trivial changes (2)
  • README.md
  • test/fixtures/apps/app-listen-reusePort/package.json
🧰 Additional context used
🪛 Biome
lib/app_worker.js

[error] 38-38: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

test/fixtures/apps/app-listen-reusePort/app.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

test/fixtures/apps/app-listen-reusePort/config/config.default.js

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

🔇 Additional comments (8)
test/fixtures/apps/app-listen-reusePort/app.js (2)

1-2: Keep the 'use strict' directive.

While modules are automatically in strict mode and the static analysis flags this as redundant, it's common practice in Node.js projects to keep explicit strict mode declarations for consistency and backwards compatibility.

🧰 Tools
🪛 Biome

[error] 1-1: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)


3-6: 🛠️ Refactor suggestion

Consider using a public API to configure the port.

The code directly modifies the internal _options property, which could be fragile if the internal API changes. Consider checking if there's a public API method to configure the port.

Let's check if there's a public API available:

If a public API exists, consider refactoring to:

-  app._options.port = undefined;
+  app.setPort(undefined); // or equivalent public API
✅ Verification successful

Based on the search results and the context from the test files, I can now generate the final response:

The direct modification of _options.port is the intended way in test fixtures

The code is in a test fixture that deliberately unsets the port to test specific server binding scenarios. This is a valid use case because:

  1. The port configuration is primarily handled through the cluster configuration in config.default.js files, as seen in multiple test fixtures.
  2. The _options property is part of the framework's internal API used consistently across test files for port configuration.
  3. Test fixtures like app-listen-reusePort, app-listen-without-port, and others follow the same pattern to test different port binding scenarios.

No public API exists specifically for modifying the port after initialization, as this is typically configured through the application's configuration files rather than programmatically.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for port configuration methods in the codebase
rg -A 5 "prototype.*[pP]ort" 

Length of output: 30


Script:

#!/bin/bash
# Let's try a broader search for port-related configurations and methods
rg -i "\.port" -A 5

# Also search for port-related configurations in the test files
rg -i "port.*=|set.*port" test/ -A 5

# Look for Application class definition and port-related methods
ast-grep --pattern 'class Application {
  $$$
}'

Length of output: 46714


Script:

#!/bin/bash
# Let's search for port configuration in the Application class and related files
rg -l "class.*Application" | xargs rg -A 5 "port"

# Look for port configuration methods in lib directory
rg -A 5 "prototype.*port|set.*port" lib/

# Search for configuration documentation
rg -i "port.*configuration|configure.*port" -g "*.md"

Length of output: 975

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

3-11: LGTM! Configuration matches PR requirements.

The configuration correctly implements the reusePort feature as specified in issue #5365. The port number is appropriate for testing purposes.

Note: While using a simple string '123' as keys is acceptable for test fixtures, ensure that production configurations use strong, unique keys.

Let's verify this is indeed a test-only configuration:

✅ Verification successful

Configuration verified as test-only with appropriate test coverage

The configuration is correctly placed and used:

  • Located exclusively in test fixtures directory
  • Port 17010 is not used in production code
  • The reusePort feature is properly tested in multiple test files including master.test.js and app_worker.test.js
  • The configuration structure follows the test fixture pattern with appropriate test-only values
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify this is a test-only configuration by checking its path
# and ensuring no production code references this keys value

# Test 1: Confirm this is under test directory
if ! echo "test/fixtures/apps/app-listen-reusePort/config/config.default.js" | grep -q "^test/"; then
    echo "Warning: Configuration file not in test directory"
fi

# Test 2: Check for any usage of this keys value in non-test code
rg -g '!test/**' "'123'" 

Length of output: 123


Script:

#!/bin/bash
# Let's verify this more thoroughly with multiple checks

# Check 1: Look for any similar config files in non-test directories
fd "config.default.js" --exclude test/

# Check 2: Search for any usage of port 17010 in non-test code
rg -g '!test/**' "17010"

# Check 3: Look for all files in this test fixture directory to understand its scope
fd . test/fixtures/apps/app-listen-reusePort/

# Check 4: Check if there are other test configurations using reusePort for comparison
rg "reusePort.*true" test/

Length of output: 796

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

1-9: LGTM - Test fixture implementation is appropriate.

The router implementation provides the necessary endpoints to validate the reusePort functionality in the test environment.

.github/workflows/nodejs.yml (1)

15-15: LGTM! Verify Node.js 23 support in the reusable workflow.

Testing against Node.js 23 is valuable for catching compatibility issues early, especially for low-level socket features like SO_REUSEPORT.

Let's verify if the reusable workflow supports Node.js 23:

Note: Since Node.js 23 is currently in development, monitor CI stability and consider making it an optional test if it causes false negatives.

lib/utils/options.js (1)

15-15: Verify integration with worker and master components.

Let's ensure the reusePort option is properly handled by the dependent components.

✅ Verification successful

Based on the results, I can now generate the final response since I have sufficient information about how the reusePort option is integrated:

Integration with worker and master components is properly implemented

The reusePort option is correctly handled:

  • In lib/master.js, it's properly documented with platform compatibility notes
  • In lib/app_worker.js, it's properly:
    • Merged with listen config: options.reusePort = options.reusePort || listenConfig.reusePort
    • Used in server creation: server.listen(listenOptions) with listenOptions containing the reusePort setting
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of reusePort option in worker and master components

echo "Checking reusePort usage in app_worker.js and master.js:"
rg -A 5 "reusePort" "lib/app_worker.js" "lib/master.js"

echo -e "\nChecking server creation and listening logic:"
ast-grep --pattern 'server.listen($$$)'

Length of output: 2238

test/app_worker.test.js (1)

236-236: Verify test app configuration.

Let's ensure the test app is properly configured for reusePort testing.

✅ Verification successful

Test app configuration is properly set for reusePort testing

The test app is correctly configured with:

  • reusePort: true in config.default.js
  • Custom port 17010 to avoid egg-mock's default port
  • Working HTTP endpoint verified in the test implementation
  • Proper cluster setup and port verification in the test
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check test app configuration for reusePort setting

# Test: Verify the test app has proper configuration
echo "Checking test app configuration..."
rg -A 5 "reusePort" "test/fixtures/apps/app-listen-reusePort/config/"

# Test: Check if the app has necessary test endpoints
echo "Checking test endpoints..."
rg -A 5 "app.get\('/(?:reusePort|pid)'" "test/fixtures/apps/app-listen-reusePort/"

Length of output: 596


Script:

#!/bin/bash
# Let's check the app configuration and implementation more thoroughly

# Check the complete config file content
echo "Checking complete config file..."
cat test/fixtures/apps/app-listen-reusePort/config/config.default.js

# Check the app implementation
echo -e "\nChecking app implementation..."
cat test/fixtures/apps/app-listen-reusePort/app.js

# Check the test file using this app
echo -e "\nChecking test implementation..."
cat test/app_worker.test.js | grep -A 10 "app-listen-reusePort"

Length of output: 987

lib/master.js (1)

Line range hint 447-467: Verify sticky mode compatibility with reusePort.

The startMasterSocketServer method needs to be verified for compatibility when both sticky mode and reusePort are enabled. The current implementation might need adjustments to handle connection distribution correctly in this scenario.

Let's verify the implementation:

@codecov
Copy link

codecov bot commented Oct 26, 2024

Codecov Report

❌ Patch coverage is 70.16129% with 37 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.50%. Comparing base (7c6ebfa) to head (9e99e6f).

Files with missing lines Patch % Lines
lib/utils/mode/impl/worker_threads/app.js 36.36% 35 Missing ⚠️
lib/app_worker.js 94.73% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              2.x     #115      +/-   ##
==========================================
- Coverage   92.52%   91.50%   -1.03%     
==========================================
  Files          15       15              
  Lines        2021     2106      +85     
  Branches      336      346      +10     
==========================================
+ Hits         1870     1927      +57     
- Misses        151      179      +28     

☔ 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.

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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 3d8d116 and dd45194.

📒 Files selected for processing (1)
  • test/app_worker.test.js (1 hunks)
🧰 Additional context used
🪛 GitHub Check: Node.js / Test (ubuntu-latest, 23)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

🪛 GitHub Check: Node.js / Test (ubuntu-latest, 22)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

🪛 GitHub Check: Node.js / Test (macos-latest, 23)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

🪛 GitHub Check: Node.js / Test (ubuntu-latest, 20)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

🪛 GitHub Check: Node.js / Test (ubuntu-latest, 18)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

🪛 GitHub Check: Node.js / Test (ubuntu-latest, 16)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

🪛 GitHub Check: Node.js / Test (ubuntu-latest, 14)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

🪛 GitHub Check: Node.js / Test (macos-latest, 22)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

🪛 GitHub Check: Node.js / Test (macos-latest, 20)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

🪛 GitHub Check: Node.js / Test (macos-latest, 16)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

🪛 GitHub Check: Node.js / Test (macos-latest, 14)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

🪛 GitHub Check: Node.js / Test (macos-latest, 18)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

🪛 Biome
test/app_worker.test.js

[error] 235-235: Don't focus the test.

The 'only' method is often used for debugging or during implementation. It should be removed before deploying to production.
Consider removing 'only' to ensure all tests are executed.
Unsafe fix: Remove focus from test.

(lint/suspicious/noFocusedTests)

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: 5

🧹 Outside diff range and nitpick comments (2)
lib/agent_worker.js (1)

Line range hint 1-58: Architecture feedback regarding reusePort integration

While the error handling improvements are solid, consider adding debug logs specifically for reusePort-related initialization since this file is part of the worker management system that will be affected by the new reusePort feature. This would help in troubleshooting port binding issues in distributed deployments.

Consider adding debug logs like:

 try {
+  debug('initializing agent with reusePort: %j', options.reusePort);
   agent = new Agent(options);
 } catch (err) {
   consoleLogger.error(err);
lib/app_worker.js (1)

43-47: Document platform limitation in README.

The platform check correctly limits reusePort to Linux systems. However, this limitation should be documented in the README to set proper expectations for users.

Would you like me to help draft the documentation for the platform limitation?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between dd45194 and cb897b6.

📒 Files selected for processing (5)
  • lib/agent_worker.js (1 hunks)
  • lib/app_worker.js (3 hunks)
  • lib/utils/options.js (1 hunks)
  • package.json (1 hunks)
  • test/reuseport_cluster.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/utils/options.js
🧰 Additional context used
🪛 Biome
lib/app_worker.js

[error] 42-42: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

🪛 GitHub Check: codecov/patch
lib/app_worker.js

[warning] 133-138: lib/app_worker.js#L133-L138
Added lines #L133 - L138 were not covered by tests


[warning] 142-143: lib/app_worker.js#L142-L143
Added lines #L142 - L143 were not covered by tests

🔇 Additional comments (7)
lib/agent_worker.js (3)

27-27: LGTM: Improved logging context

The debug logger identifier change from 'egg-cluster' to 'egg-cluster:agent_worker' provides better context for debugging, making it easier to trace issues in distributed environments.


Line range hint 39-43: LGTM: Well-structured error handler

The startErrorHandler function effectively centralizes error handling logic during agent initialization. It provides clear error logging and ensures proper process termination.


Line range hint 45-51: Verify error handling cleanup

The error handling flow looks good, but let's verify that the error listener cleanup is comprehensive.

Also applies to: 54-54

✅ Verification successful

Based on the results, I can now generate the final response:

Error handling and cleanup implementation is correct and comprehensive

The error handling flow is properly implemented with a clear pattern:

  • The startErrorHandler is registered using once() which automatically removes the listener after first trigger
  • The explicit removeListener() is correctly used to clean up when agent starts successfully
  • No conflicting error handlers found in the agent worker context
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any other error handler registrations or potential memory leaks
# Test: Search for other error event handlers that might conflict
rg -A 5 "\.on\('error'" || rg -A 5 "\.once\('error'"

# Test: Check for proper cleanup patterns
rg -A 5 "removeListener\('error'"

Length of output: 1472

package.json (1)

11-11: Verify test framework compatibility with reuseport tests.

Let's ensure the reuseport tests can be properly integrated with egg-bin test framework.

test/reuseport_cluster.js (1)

1-4: LGTM! Proper use of node: protocol prefix for imports.

The module imports are well-structured and follow Node.js best practices by using the node: protocol prefix for core modules.

lib/app_worker.js (2)

19-21: LGTM! Improved logging granularity.

The debug namespace change from 'egg-cluster' to 'egg-cluster:app_worker' provides better log segmentation, making it easier to filter worker-specific logs.


132-146: Add test coverage for hostname configuration.

The code paths for hostname configuration (lines 134-136, 141-143) lack test coverage. Please add tests for:

  • reusePort with hostname configuration
  • reusePort without hostname configuration
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 133-138: lib/app_worker.js#L133-L138
Added lines #L133 - L138 were not covered by tests


[warning] 142-143: lib/app_worker.js#L142-L143
Added lines #L142 - L143 were not covered by tests

@dennisleung
Copy link

请问reuseport还没合入吗?

@fengmk2
Copy link
Member Author

fengmk2 commented Dec 1, 2025

@dennisleung 还没,因为测试了一下性能没有变化,所以暂时还没动力合并。
你是有什么特殊场景需要用到它吗?

@fengmk2 fengmk2 changed the base branch from master to 2.x December 1, 2025 06:21
@fengmk2
Copy link
Member Author

fengmk2 commented Dec 12, 2025

https://blog.platformatic.dev/93-faster-nextjs-in-your-kubernetes 看来是我的测试方式不对,周末改成短连接的方式再次验证一下

@fengmk2 fengmk2 requested a review from Copilot December 12, 2025 16:12
@fengmk2 fengmk2 self-assigned this Dec 12, 2025
fengmk2 and others added 2 commits December 13, 2025 00:13
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: MK (fengmk2) <[email protected]>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: MK (fengmk2) <[email protected]>
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 support for the reusePort option in server listen configuration, allowing multiple worker processes to bind to the same port with load balancing handled by the operating system. This is a Linux-focused feature (currently) that can improve performance in multi-worker scenarios.

Key Changes

  • Added reusePort option with platform detection (Linux only in implementation)
  • Updated server listen logic to use reusePort when enabled
  • Added test coverage for the new feature including integration tests and manual cluster test

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
lib/app_worker.js Implements reusePort logic with platform check and modified server.listen() call
lib/master.js Adds JSDoc documentation for the reusePort option
lib/utils/options.js Sets default value of reusePort to false
lib/agent_worker.js Updates debug logger name for better specificity
test/app_worker.test.js Adds integration test for reusePort configuration
test/master.test.js Adds test for master startup with reusePort enabled
test/reuseport_cluster.js New manual cluster test demonstrating reusePort functionality
test/fixtures/apps/app-listen-reusePort/* Test fixture app with reusePort configuration
package.json Adds manual cluster test to CI pipeline
.github/workflows/nodejs.yml Adds Node.js v23 to test matrix
README.md Fixes codecov badge URLs

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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

♻️ Duplicate comments (2)
package.json (2)

11-11: Guard test/reuseport_cluster.js in CI to avoid non-Linux failures/flakes.

If your CI runs on macOS/Windows, this step can fail or behave inconsistently; prefer gating to Linux (or make the test self-skip when reusePort isn’t supported).

-    "ci": "npm run lint && node test/reuseport_cluster.js && npm run cov"
+    "ci": "npm run lint && (node -e \"process.platform==='linux' ? process.exit(0) : process.exit(42)\" || true) && ( [ \"$(uname)\" = \"Linux\" ] && node test/reuseport_cluster.js || echo 'Skipping reuseport_cluster test: not Linux' ) && npm run cov"

(If your CI shell isn’t bash, do the platform guard inside test/reuseport_cluster.js instead.)


11-11: Prefer running reusePort coverage via the existing test runner for consistency.

Running a standalone Node script in ci bypasses the normal test reporting/coverage flow; consider moving this into egg-bin test (e.g., an integration test file) and calling it via test-local.

🧹 Nitpick comments (1)
lib/utils/options.js (1)

78-78: Use console.warn for consistency.

Line 50 in this file uses console.warn for deprecation messages. For consistency, platform incompatibility warnings should also use console.warn.

-      console.log('platform %s is not support currently, set reusePort to false', os.platform());
+      console.warn('[egg-cluster] platform %s does not support reusePort, disabled', os.platform());
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eadbdc9 and 16b546a.

📒 Files selected for processing (9)
  • .github/workflows/nodejs.yml (1 hunks)
  • .gitignore (1 hunks)
  • README.md (2 hunks)
  • lib/app_worker.js (3 hunks)
  • lib/utils/mode/impl/worker_threads/app.js (1 hunks)
  • lib/utils/options.js (3 hunks)
  • package.json (2 hunks)
  • test/app_worker.test.js (1 hunks)
  • test/fixtures/apps/app-listen-reusePort/config/config.default.js (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🚧 Files skipped from review as they are similar to previous changes (4)
  • test/app_worker.test.js
  • lib/app_worker.js
  • .github/workflows/nodejs.yml
  • test/fixtures/apps/app-listen-reusePort/config/config.default.js
🧰 Additional context used
🧬 Code graph analysis (2)
lib/utils/options.js (2)
test/reuseport_cluster.js (1)
  • cluster (1-1)
lib/utils/mode/impl/process/app.js (2)
  • cluster (3-3)
  • require (8-8)
lib/utils/mode/impl/worker_threads/app.js (2)
lib/app_worker.js (1)
  • options (4-4)
lib/agent_worker.js (1)
  • options (12-12)
⏰ 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). (8)
  • GitHub Check: Node.js / Test (ubuntu-latest, 22)
  • GitHub Check: Node.js / Test (macos-latest, 24)
  • GitHub Check: Node.js / Test (ubuntu-latest, 24)
  • GitHub Check: Node.js / Test (macos-latest, 22)
  • GitHub Check: Node.js / Test (ubuntu-latest, 20)
  • GitHub Check: Node.js / Test (macos-latest, 20)
  • GitHub Check: Node.js / Test (macos-latest, 18)
  • GitHub Check: Node.js / Test (ubuntu-latest, 18)
🔇 Additional comments (4)
package.json (1)

19-31: Repo/bugs/homepage URL updates look consistent.

These metadata links now point to eggjs/cluster, matching the PR context.

lib/utils/mode/impl/worker_threads/app.js (1)

158-176: LGTM! The conditional forking logic correctly implements reusePort support.

The implementation properly branches based on reusePort:

  • When enabled: spawns N workers with identical options, allowing SO_REUSEPORT to distribute connections
  • When disabled: preserves the per-port worker allocation strategy
lib/utils/options.js (1)

74-84: The reusePort handling logic is sound.

The implementation correctly:

  • Disables reusePort on non-Linux platforms
  • Sets cluster.schedulingPolicy = cluster.SCHED_NONE on Linux to delegate load balancing to the kernel when using SO_REUSEPORT
README.md (1)

56-56: No action required. The Node.js version requirement for reusePort is accurate. The server.listen({ reusePort }) option was indeed added in Node.js v22.12.0, making the README.md documentation correct.

Likely an incorrect or invalid review comment.

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: 3

♻️ Duplicate comments (3)
lib/app_worker.js (2)

136-136: CRITICAL: Remove trailing whitespace causing CI failures.

Line 136 contains trailing whitespace that is causing all CI checks to fail. This must be fixed before the PR can be merged.

Apply this diff:

-        // https://nodejs.org/api/net.html#serverlistenoptions-callback
+        // https://nodejs.org/api/net.html#serverlistenoptions-callback

(Remove the trailing space(s) at the end of the comment line)


43-43: Add type validation for reusePort option.

While port validation exists (lines 129-133), there's no validation for the reusePort option. This could lead to unexpected behavior if a non-boolean value is passed.

Apply this diff to add type validation before using reusePort:

 let reusePort = options.reusePort = options.reusePort || listenConfig.reusePort;
+if (reusePort && typeof reusePort !== 'boolean') {
+  consoleLogger.error('[app_worker] reusePort should be boolean, but got %s(%s)', reusePort, typeof reusePort);
+  exitProcess();
+  return;
+}
 if (reusePort && os.platform() !== 'linux') {
lib/utils/mode/impl/worker_threads/app.js (1)

179-181: Validate port is defined when ports array is empty.

When reusePort is false and ports array is empty, this.options.port is pushed into the array. However, this.options.port can be undefined, causing workers to attempt listening on an undefined port.

Apply this diff to add validation:

       const ports = this.options.ports;
       if (!ports.length) {
+        if (!this.options.port) {
+          throw new Error('options.port must be specified when ports array is empty');
+        }
         ports.push(this.options.port);
🧹 Nitpick comments (1)
lib/app_worker.js (1)

44-49: Expand reusePort platform support beyond Linux.

The current implementation restricts reusePort to Linux only, but Node.js documentation indicates reusePort is available on Linux 3.9+, DragonFlyBSD 3.6+, FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+. Either expand platform support to match Node.js capabilities or document why only Linux is currently supported.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d1c0d2d and 6ef351c.

📒 Files selected for processing (3)
  • lib/app_worker.js (3 hunks)
  • lib/utils/mode/impl/worker_threads/app.js (3 hunks)
  • lib/utils/options.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/utils/options.js
🧰 Additional context used
🧬 Code graph analysis (2)
lib/utils/mode/impl/worker_threads/app.js (4)
lib/app_worker.js (2)
  • options (4-4)
  • AppWorker (12-12)
lib/utils/messenger.js (1)
  • workerThreads (4-4)
lib/utils/mode/impl/worker_threads/agent.js (1)
  • workerThreads (3-3)
test/fixtures/apps/agent-worker-threads/agent.js (1)
  • workerThreads (3-3)
lib/app_worker.js (4)
lib/utils/options.js (2)
  • os (3-3)
  • fs (4-4)
lib/master.js (3)
  • os (3-3)
  • require (10-10)
  • fs (7-7)
test/options.test.js (1)
  • os (3-3)
test/fixtures/apps/cluster_mod_sticky/app.js (1)
  • server (8-8)
⏰ 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). (8)
  • GitHub Check: Node.js / Test (macos-latest, 24)
  • GitHub Check: Node.js / Test (macos-latest, 18)
  • GitHub Check: Node.js / Test (ubuntu-latest, 24)
  • GitHub Check: Node.js / Test (macos-latest, 22)
  • GitHub Check: Node.js / Test (ubuntu-latest, 18)
  • GitHub Check: Node.js / Test (ubuntu-latest, 20)
  • GitHub Check: Node.js / Test (macos-latest, 20)
  • GitHub Check: Node.js / Test (ubuntu-latest, 22)
🔇 Additional comments (2)
lib/app_worker.js (1)

19-23: LGTM!

The os module import is correctly added to support platform detection for reusePort, and the debug namespace update aligns with the module naming.

lib/utils/mode/impl/worker_threads/app.js (1)

194-201: LGTM!

The kill method correctly sets disableRefork before terminating workers, preventing unwanted reforks. Listener cleanup is appropriate to avoid memory leaks.

fengmk2 and others added 6 commits December 13, 2025 11:15
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: MK (fengmk2) <[email protected]>
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: 1

♻️ Duplicate comments (1)
lib/utils/mode/impl/worker_threads/app.js (1)

174-195: Good: reusePort now fails fast without options.port.
Nice preflight check (Line 175-177); prevents forking workers that can’t listen.

Still missing: guard against undefined port when reusePort is false and ports is empty.
This keeps the old footgun: ports.push(this.options.port) (Line 185-187) can still push undefined and later fork workers with invalid port.

     } else {
       const ports = this.options.ports;
       if (!ports.length) {
+        if (!this.options.port) {
+          throw new Error('options.port must be specified when reusePort is disabled and ports is empty');
+        }
         ports.push(this.options.port);
       }
       this.options.workers = ports.length;
       let i = 0;
🧹 Nitpick comments (1)
lib/utils/mode/impl/worker_threads/app.js (1)

200-206: kill() should await terminate() and clear internal state.
Worker#terminate() returns a Promise; not awaiting can cause callers to proceed while threads are still alive. Also consider clearing #appWorkers once termination is initiated/completed.

   async kill() {
-    for (const appWorker of this.#appWorkers) {
+    const terminating = [];
+    for (const appWorker of this.#appWorkers) {
       this.log('[master] kill app_worker#%s (tid:%s) (worker_threads) by worker.terminate()', appWorker.id, appWorker.workerId);
       appWorker.disableRefork = true;
       appWorker.instance.removeAllListeners();
-      appWorker.instance.terminate();
+      terminating.push(appWorker.instance.terminate());
     }
+    await Promise.allSettled(terminating);
+    this.#appWorkers = [];
   }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 35bb21a and 6490b75.

📒 Files selected for processing (2)
  • lib/utils/mode/impl/worker_threads/app.js (3 hunks)
  • test/reuseport_cluster.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/reuseport_cluster.js
⏰ 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). (11)
  • GitHub Check: Node.js / Test (ubuntu-latest, 24)
  • GitHub Check: Node.js / Test (ubuntu-latest, 22)
  • GitHub Check: Node.js / Test (macos-latest, 14)
  • GitHub Check: Node.js / Test (macos-latest, 20)
  • GitHub Check: Node.js / Test (macos-latest, 24)
  • GitHub Check: Node.js / Test (macos-latest, 18)
  • GitHub Check: Node.js / Test (ubuntu-latest, 20)
  • GitHub Check: Node.js / Test (macos-latest, 22)
  • GitHub Check: Node.js / Test (ubuntu-latest, 18)
  • GitHub Check: Node.js / Test (ubuntu-latest, 14)
  • GitHub Check: Node.js / Test (ubuntu-latest, 16)
🔇 Additional comments (1)
lib/utils/mode/impl/worker_threads/app.js (1)

74-82: Rename to #appWorkers is clear and consistent with “app worker” semantics.

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: 1

♻️ Duplicate comments (2)
test/app_worker.test.js (1)

235-262: Remove it.only and comment out debug call.

This test still uses it.only which blocks all other tests from running, causing CI failures. The app.debug() call should also be commented out for cleaner test output.

Apply this diff:

-    it.only('should set reusePort=true in config', async () => {
+    it('should set reusePort=true in config', async () => {
       app = utils.cluster('apps/app-listen-reusePort');
-      app.debug();
+      // app.debug();
       await app.ready();
lib/app_worker.js (1)

43-53: Add DragonFlyBSD to supported platforms list.

The comment on line 46 mentions "DragonFlyBSD 3.6+" but the supportedPlatforms array is missing 'dragonfly'. Node.js returns 'dragonfly' from os.platform() on DragonFlyBSD systems.

Apply this diff:

 // 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 supportedPlatforms = [ 'linux', 'freebsd', 'sunos', 'aix' ];
+const supportedPlatforms = [ 'linux', 'freebsd', 'sunos', 'aix', 'dragonfly' ];
🧹 Nitpick comments (1)
lib/app_worker.js (1)

146-153: Use %j formatter for array in debug statement.

Line 151 uses %s for the args array, which won't display the array structure properly. For consistency with line 144 and better debug output, use %j.

Apply this diff:

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

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6490b75 and 72133ca.

📒 Files selected for processing (3)
  • lib/app_worker.js (3 hunks)
  • test/app_worker.test.js (1 hunks)
  • test/master.test.js (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
lib/app_worker.js (4)
lib/utils/options.js (2)
  • os (3-3)
  • fs (4-4)
lib/master.js (4)
  • os (3-3)
  • require (10-10)
  • fs (7-7)
  • ConsoleLogger (11-11)
test/options.test.js (1)
  • os (3-3)
lib/agent_worker.js (3)
  • debug (27-27)
  • ConsoleLogger (28-28)
  • options (12-12)
test/master.test.js (1)
test/fixtures/apps/script-start/start-server.js (2)
  • app (5-5)
  • utils (2-2)
🪛 GitHub Check: Node.js / Test (macos-latest, 16)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

test/master.test.js

[warning] 32-32:
it.only not permitted


[warning] 32-32:
it.only not permitted

🪛 GitHub Check: Node.js / Test (macos-latest, 18)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

test/master.test.js

[warning] 32-32:
it.only not permitted


[warning] 32-32:
it.only not permitted

🪛 GitHub Check: Node.js / Test (macos-latest, 22)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

test/master.test.js

[warning] 32-32:
it.only not permitted


[warning] 32-32:
it.only not permitted

🪛 GitHub Check: Node.js / Test (macos-latest, 24)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

test/master.test.js

[warning] 32-32:
it.only not permitted


[warning] 32-32:
it.only not permitted

🪛 GitHub Check: Node.js / Test (ubuntu-latest, 14)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

test/master.test.js

[warning] 32-32:
it.only not permitted


[warning] 32-32:
it.only not permitted

🪛 GitHub Check: Node.js / Test (ubuntu-latest, 16)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

test/master.test.js

[warning] 32-32:
it.only not permitted


[warning] 32-32:
it.only not permitted

🪛 GitHub Check: Node.js / Test (ubuntu-latest, 18)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

test/master.test.js

[warning] 32-32:
it.only not permitted


[warning] 32-32:
it.only not permitted

🪛 GitHub Check: Node.js / Test (ubuntu-latest, 20)
test/app_worker.test.js

[warning] 235-235:
it.only not permitted


[warning] 235-235:
it.only not permitted

test/master.test.js

[warning] 32-32:
it.only not permitted


[warning] 32-32:
it.only not permitted

⏰ 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). (4)
  • GitHub Check: Node.js / Test (macos-latest, 20)
  • GitHub Check: Node.js / Test (ubuntu-latest, 24)
  • GitHub Check: Node.js / Test (macos-latest, 14)
  • GitHub Check: Node.js / Test (ubuntu-latest, 22)
🔇 Additional comments (1)
lib/app_worker.js (1)

138-145: LGTM - reusePort listen implementation is well-structured.

The implementation correctly builds the listen options with port and reusePort, and properly includes host when listenConfig.hostname is set. This aligns well with the Node.js server.listen(options) API.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/utils/mode/impl/process/app.js (1)

129-142: Fix the action name mismatch in the message handler and add deduplication to prevent double app-start.

The code has two potential paths for emitting app-start: one via cluster.on('listening') and another via cluster.on('message'). Currently, the message handler checks for action !== 'reuse-port-listening', but the worker sends action: 'listening'. If the action name is corrected, both handlers could fire simultaneously when reusePort is enabled, causing duplicate app-start emissions. Either fix the action name and implement deduplication (via Set keyed by worker.id or pid), or ensure only one code path handles the listening event based on the reusePort flag.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 545a442 and 0da63a6.

📒 Files selected for processing (2)
  • lib/app_worker.js (4 hunks)
  • lib/utils/mode/impl/process/app.js (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/app_worker.js
⏰ 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). (3)
  • GitHub Check: Node.js / Test (macos-latest, 18)
  • GitHub Check: Node.js / Test (ubuntu-latest, 22)
  • GitHub Check: Node.js / Test (ubuntu-latest, 24)

@fengmk2
Copy link
Member Author

fengmk2 commented Dec 13, 2025

/gemini review

Copy link

@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 reusePort option, enabling multiple sockets to bind to the same port for improved load distribution. Key changes include adding the reusePort option to the cluster configuration and documentation, implementing platform-specific reusePort logic in app_worker.js for server listening, and adapting worker forking and listening event handling in worker_threads/app.js and process/app.js to accommodate this new feature. The debuglog namespaces were updated, pnpm-lock.yaml was added to .gitignore, and package metadata was revised. New test cases were added to verify the reusePort functionality. Review comments highlighted the omission of 'dragonfly' from the supportedPlatforms array in app_worker.js, suggested refactoring a do-while loop to a for loop in worker_threads/app.js for better readability, and recommended replacing the deprecated cluster.isMaster with cluster.isPrimary in a test script.

// 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 supportedPlatforms = [ 'linux', 'freebsd', 'sunos', 'aix' ];

Choose a reason for hiding this comment

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

high

The supportedPlatforms array is missing support for DragonFlyBSD. The README.md mentions it as a supported platform, but os.platform() returns 'dragonfly', which is not in this list. This will prevent reusePort from being enabled on that platform.

Suggested change
const supportedPlatforms = [ 'linux', 'freebsd', 'sunos', 'aix' ];
const supportedPlatforms = [ 'linux', 'freebsd', 'sunos', 'aix', 'dragonfly' ];

Comment on lines +189 to +194
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);

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 used here is a bit unconventional and less readable than a standard for loop for this kind of iteration. Using a for loop would make the intent clearer and improve maintainability.

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

});
}

if (cluster.isPrimary || cluster.isMaster) {

Choose a reason for hiding this comment

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

medium

cluster.isMaster has been deprecated since Node.js v16.0.0. It's better to use cluster.isPrimary for forward compatibility and to adhere to modern Node.js practices.

Suggested change
if (cluster.isPrimary || cluster.isMaster) {
if (cluster.isPrimary) {

@fengmk2 fengmk2 merged commit c691907 into 2.x Dec 13, 2025
29 of 30 checks passed
@fengmk2 fengmk2 deleted the reuse-port branch December 13, 2025 09:06
fengmk2 pushed a commit that referenced this pull request Dec 13, 2025
[skip ci]

## 2.5.0 (2025-12-13)

* chore: change default branch to master ([9aac416](9aac416))
* chore: fix auto release ([7c6ebfa](7c6ebfa))
* feat: support reusePort on server listen (#115) ([c691907](c691907)), closes [#115](#115) [hi#level](https://github.com/hi/issues/level)
@github-actions
Copy link

🎉 This PR is included in version 2.5.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

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.

跟进 SO_REUSEPORT

3 participants