Repository navigation
Cannot set up cluster.schedulingPolicy in ESM #49240
Description
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:
import * as cluster from 'cluster'
if (cluster.isPrimary) {
process.env.NODE_CLUSTER_SCHED_POLICY = 'none'
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)
}cluster-error.txt
Attached as cluster-error.txt. You will see that it prints the following:
$ node cluster-error.js
process.env.NODE_CLUSTER_SCHED_POLICY: 'none'
cluster.schedulingPolicy: 2
cluster.schedulingPolicy: 2So the env variable NODE_CLUSTER_SCHED_POLICY has no effect, cluster.schedulingPolicy has the value 2 which is the default cluster.SCHED_RR. However running it with the env variable from the console works as expected:
$ NODE_CLUSTER_SCHED_POLICY='none' node cluster-error.js
process.env.NODE_CLUSTER_SCHED_POLICY: none
cluster.schedulingPolicy: 1
cluster.schedulingPolicy: 1I cannot set the cluster.schedulingPolicy as per the docs: cluster.schedulingPolicy = cluster.SCHED_NONE since the cluster module is imported:
import * as cluster from 'cluster'
cluster.schedulingPolicy = cluster.SCHED_NONEso I get a TypeError:
cluster.schedulingPolicy = cluster.SCHED_NONE
^
TypeError: Cannot assign to read only property 'schedulingPolicy' of object '[object Module]'
at file:///home/alex/projects/loadtest/cluster-error.js:2:26
at ModuleJob.run (node:internal/modules/esm/module_job:194:25)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. the cluster.schedulingPolicy is set to 1 cluster.SCHED_NONE:
$ node cluster-error.js
process.env.NODE_CLUSTER_SCHED_POLICY: none
cluster.schedulingPolicy: 1
cluster.schedulingPolicy: 1(Fake output.)
What do you see instead?
Instead I see cluster.schedulingPolicy has the default value of 2 cluster.SCHED_RR:
$ node cluster-error.js
process.env.NODE_CLUSTER_SCHED_POLICY: none
cluster.schedulingPolicy: 2
cluster.schedulingPolicy: 2Additional 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 none mode 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.schedulingPolicy does not work. I would think that the best solution is to have a setting in cluster.settings that can be set with cluster.setupPrimary([settings]). As suggested by @bnoordhuis in this hopeful comment.
Activity
alexfernandez commentedon Aug 19, 2023
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: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.[-]Cannot set up `cluster.schedulingPolicy` in a JS module (with import)[/-][+]Cannot set up `cluster.schedulingPolicy` in ESM[/+]aduh95 commentedon 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?alexfernandez commentedon Aug 19, 2023
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.aduh95 commentedon Aug 19, 2023
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.alexfernandez commentedon Aug 19, 2023
Sure, it works as expected. For reference, the code is:
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.aduh95 commentedon Aug 19, 2023
Sure, sending a PR would be fantastic :)
alexfernandez commentedon Aug 20, 2023
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:I have a preliminary implementation ready that I can post for comments, only the documentation is missing. Is this going too far?
aduh95 commentedon Aug 20, 2023
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.alexfernandez commentedon Aug 20, 2023
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:
schedulingPolicyintocluster.settings: alexfernandez@4a3b344.cluster.getSettings(): alexfernandez@36d4de7.cluster.setPrimary({schedulingPolicy})andcluster.getSettings(): alexfernandez@23a309a.Thanks!
benjamingr commentedon Aug 20, 2023
@nodejs/cluster
bnoordhuis commentedon Aug 20, 2023
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.alexfernandez commentedon Aug 20, 2023
@bnoordhuis Thanks for the feedback!
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.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.bnoordhuis commentedon Aug 20, 2023
I usually take a very reactive approach: don't do anything until users start filing bug reports :-)
2 remaining items
alexfernandez commentedon Aug 22, 2023
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 commentedon May 28, 2026
This 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.
github-actions commentedon Jun 28, 2026
This 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.
cluster: fold schedulingPolicy into cluster.settings
cluster: fold schedulingPolicy into cluster.settings
github-actions commentedon Sep 28, 2026
This 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.