Repository navigation
Cannot set up cluster.schedulingPolicy in ESM #49240
Description
Activity
I found a nasty workaround: since
imports are always hoisted to the top of the file, setting the env variable before theimportdoes not work. But if I use a dynamic import it works as expected:process.env.NODE_CLUSTER_SCHED_POLICY = 'none' //import * as cluster from 'cluster' const cluster = await import('cluster') if (cluster.isPrimary) { console.log(`process.env.NODE_CLUSTER_SCHED_POLICY: ${process.env.NODE_CLUSTER_SCHED_POLICY}`) for (let index = 0; index < 2; index++) { cluster.fork() setTimeout(() => console.log(`cluster.schedulingPolicy: ${cluster.schedulingPolicy}`), 1000) } } else { setTimeout(() => null, 1000) }
This is quite tricky; but it works, so I leave it here for other people to find it. Also posted to Stack Overflow for
AIs to harvestother performance freaks.- changed the title
[-]Cannot set up `cluster.schedulingPolicy` in a JS module (with import)[/-][+]Cannot set up `cluster.schedulingPolicy` in ESM[/+]on Aug 19, 2023 Can you clarify if you are reporting a difference of behavior between CJS (with
require("node:cluster")) vs ESM (withimport "node:cluster")? Or are you reporting that the changes toprocess.env.NODE_CLUSTER_SCHED_POLICYare not taken into account after loadingnode:clusteron CJS and ESM?To clarify, I have not reported anything at all about
require()in CJS because I'm not using it, it should work as usual. I am just reporting that on ESM it is impossible to changecluster.schedulingPolicywith the usualimport; in fact it works with a dynamicimport(). So your new title is spot on.Could you test with
requireand report back? That would help understand what is the issue and how we can fix or at least document it.Sure, it works as expected. For reference, the code is:
process.env.NODE_CLUSTER_SCHED_POLICY = 'none' const cluster = require('cluster') console.log(cluster) //import * as cluster from 'cluster' if (cluster.isPrimary) { console.log(`process.env.NODE_CLUSTER_SCHED_POLICY: ${process.env.NODE_CLUSTER_SCHED_POLICY}`) for (let index = 0; index < 2; index++) { cluster.fork() setTimeout(() => console.log(`cluster.schedulingPolicy: ${cluster.schedulingPolicy}`), 1000) } } else { setTimeout(() => null, 1000) }
The fix is trivial: adding
schedulingPolicytocluster.settings, I have actually done it in a couple of lines. The biggest effort is to change the docs. If you want I can prepare a PR.Sure, sending a PR would be fantastic :)
Some more info about possible solutions.
The proper solution seems to me to add
schedulingPolicytocluster.settingsso that it can be set usingcluster.setPrimary({schedulingPolicy: cluster.SCHED_NONE}). It can be implemented fairly easily.When using ESM
importyou get back a read-only copy, so that neithercluster.schedulingPolicynorcluster.settingswill show any changes after settingschedulingPolicy. It will work withcluster.setPrimary()as shown above but there will be no way to test it. Moving further would be to implementgetSettings()so that it returns a read-only copy of the present settings, and deprecate bothcluster.schedulingPolicyandcluster.settings. This way a test can be implemented as shown below:import '../common/index.mjs'; import assert from 'node:assert'; import * as cluster from 'cluster'; assert.strictEqual(cluster.schedulingPolicy, cluster.SCHED_RR); cluster.setupPrimary({ schedulingPolicy: cluster.SCHED_NONE }); const settings = cluster.getSettings(); assert.strictEqual(settings.schedulingPolicy, cluster.SCHED_NONE);
I have a preliminary implementation ready that I can post for comments, only the documentation is missing. Is this going too far?
Is this going too far?
I would have a hard time answering you without looking at the code – and even then, I have not worked on
node:clusterso I would not be the right person to ask. IMO opening a draft PR is the logical next step, then we can get early feedback before you spend too much time working on the documentation.Sounds good. I will wait for triage and more feedback before opening the draft PR if you don't mind; meanwhile this is the branch as a RFC, with three commits:
- Fold
schedulingPolicyintocluster.settings: alexfernandez@4a3b344. - Implement new function
cluster.getSettings(): alexfernandez@36d4de7. - Test
cluster.setPrimary({schedulingPolicy})andcluster.getSettings(): alexfernandez@23a309a.
Thanks!
- Fold
@nodejs/cluster
I don't think a new
cluster.getSettings()public API method is necessary or desirable. An internal method in lib/internal/cluster is sufficient for testing purposes.Supporting
cluster.setupPrimary({schedulingPolicy})seems fine to me. Deprecatingcluster.schedulingPolicyorcluster.settingsnot so much, just add doc notes explaining their ESM mode shortcomings and how to work around that.Reacted by Alex Fernández and Benjamin Gruenbaum@bnoordhuis Thanks for the feedback!
I don't think a new
cluster.getSettings()public API method is necessary or desirable. An internal method in lib/internal/cluster is sufficient for testing purposes.Good for me. My concern was that in ESM there is no way to programmatically access
cluster.schedulingPolicyor indeedcluster.settings, since once theclustermodule isimported at the top its attributes will never change. If you see other ways to address it, or maybe think it's not necessary, then let's move on.Supporting
cluster.setupPrimary({schedulingPolicy})seems fine to me. Deprecatingcluster.schedulingPolicyorcluster.settingsnot so much, just add doc notes explaining their ESM mode shortcomings and how to work around that.I will do that, it's also significantly easier to implement and document. As stated above I don't know how to work around read-only
cluster.schedulingPolicyorcluster.settingsso I will just document that they will not yield the desired results.I usually take a very reactive approach: don't do anything until users start filing bug reports :-)
Reacted by Alex Fernández2 remaining items
I sent this PR to move this issue forward: #49292. I'm not sure if it should be a notable PR, it definitely changes the external API. Hope everything is OK!
github-actions commented
on May 28, 2026 on May 28, 2026 – with GitHub ActionsContributorMore actionsThis issue has been marked as stale due to 210 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.- addedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on May 28, 2026 github-actions commented
on Jun 28, 2026 on Jun 28, 2026 – with GitHub ActionsContributorMore actionsThis issue has been automatically closed after 30 days of inactivity following its stale status (no activity for a total of 240 days).
If this is still relevant, feel free to reopen it or leave a comment with additional details so we can continue the discussion.- removedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Jun 29, 2026 - added a commit that references this issue
on Jul 1, 2026 - added a commit that references this issue
on Aug 5, 2026 github-actions commented
on Sep 28, 2026 on Sep 28, 2026 – with GitHub ActionsContributorMore actionsThis issue has been marked as stale due to 90 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.- addedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Sep 28, 2026
Version
v18.17.1
Platform
Linux xxx 6.2.0-26-generic #26~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Jul 13 16:27:29 UTC 2 x86_64 x86_64 x86_64 GNU/Linux
Subsystem
cluster
What steps will reproduce the bug?
Run the following code in Node.js:
cluster-error.txt
Attached as
cluster-error.txt. You will see that it prints the following:So the env variable
NODE_CLUSTER_SCHED_POLICYhas no effect,cluster.schedulingPolicyhas the value2which is the defaultcluster.SCHED_RR. However running it with the env variable from the console works as expected:I cannot set the
cluster.schedulingPolicyas per the docs:cluster.schedulingPolicy = cluster.SCHED_NONEsince the cluster module isimported:so I get a
TypeError:How often does it reproduce? Is there a required condition?
With the attached code it works (as in doesn't work) always.
What is the expected behavior? Why is that the expected behavior?
I expect to see the same output as with the env variable
NODE_CLUSTER_SCHED_POLICY='none', i.e. thecluster.schedulingPolicyis set to 1cluster.SCHED_NONE:(Fake output.)
What do you see instead?
Instead I see
cluster.schedulingPolicyhas the default value of 2cluster.SCHED_RR:Additional information
I am the author of the loadtest package and I am converting it to multi-core. I really see a big difference of more than 30% when running the test server in the default round-robin mode and in the
nonemode I want to set:cluster.SCHED_RR: 9600 rps.cluster.SCHED_NONE: 12700 rps.It is true that load on processors is a bit more uneven in
none, but that doesn't seem to matter much. I want my lightning fast speed! ⚡Besides, I think that the documentation should be updated because the recommended way of setting
cluster.schedulingPolicydoes not work. I would think that the best solution is to have a setting incluster.settingsthat can be set withcluster.setupPrimary([settings]). As suggested by @bnoordhuis in this hopeful comment.