-
Notifications
You must be signed in to change notification settings - Fork 30.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add scheduling policy to cluster.settings #49292
base: main
Are you sure you want to change the base?
Add scheduling policy to cluster.settings #49292
Conversation
@nodejs/cluster @bnoordhuis |
@@ -158,6 +161,10 @@ function removeHandlesForWorker(worker) { | |||
}); | |||
} | |||
|
|||
cluster.getSettings = function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs docs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bnoordhuis asked for getSettings()
to be internal in #49240 (comment), I understand it should not be documented then? From my side I think it makes sense to make it public and document it, but prefer to wait for his opinion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, internal stuff should not be in the docs. If there is anything not self-evident about it, please leave code comments, but that goes for everything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation is public property. If that method is expected to be internal, you need to make it non enumerable or whatever node.js uses to distinguish between public and internal APIs. But I still do not understand why folding a property into an existing object literal property needs a new getter to be added. The two are orthogonal. And if you make an PR for the folding and one for the API change, the former will not be encumbered by API changes discussion that always takes time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have documented the property getSettings()
so it can be made public. It needs the new getter because the old way to expose the whole object settings
does not play well with ESM, which makes the settings
object immutable. I believe the old settings
should therefore be made deprecated, but have not done so because I proposed it and nobody seconded the option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, what induces you to think that this PR is an ugly hack? It is indeed a pretty elegant solution if I may so myself, only deprecating the public use of settings
is in fact missing to be 100% right at least for me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, what induces you to think that this PR is an ugly hack? It is indeed a pretty elegant solution if I may so myself, only deprecating the public use of
settings
is in fact missing to be 100% right at least for me.
A real elegant solution would have not changed a public API to support ESM ;)
And I've not written that PR is an ugly hack ;) I've written that supporting ESM/CJS in code using cluster API (the API consumer) and expected to run on various node.js versions will require ugly hacks. And it could be avoided.
Anyhow, ESM support in cluster is still buggy. Worker as ESM module fails to init.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A real elegant solution would have not changed a public API to support ESM ;)
Good luck with that.
And I've not written that PR is an ugly hack ;) I've written that supporting ESM/CJS in code using cluster API (the API consumer) and expected to run on various node.js versions will require ugly hacks. And it could be avoided.
I await your proposal.
Anyhow, ESM support in cluster is still buggy. Worker as ESM module fails to init.
It works fine for me 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And I've not written that PR is an ugly hack ;) I've written that supporting ESM/CJS in code using cluster API (the API consumer) and expected to run on various node.js versions will require ugly hacks. And it could be avoided.
I await your proposal.
cluster.prototype.settings = function() {}
/Object.defineProperty(cluster, 'settings', { get: function () {}})
should works with ESM and CJS.
Is it prohibited in node.js internal JS code?
Anyhow, ESM support in cluster is still buggy. Worker as ESM module fails to init.
It works fine for me 🤔
Not if you use a dedicated ESM file as a cluster worker: #48578
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cluster.prototype.settings = function() {}
/Object.defineProperty(cluster, 'settings', { get: function () {}})
should works with ESM and CJS. Is it prohibited in node.js internal JS code?
You are aware that this change breaks backwards compatibility in CJS as it does not allow modifying cluster.settings
, as it used to do.
Anyhow, ESM support in cluster is still buggy. Worker as ESM module fails to init.
It works fine for me 🤔
Not if you use a dedicated ESM file as a cluster worker: #48578
Oh, of course my PR doesn't fix all issues. It fixes setting schedulingPolicy
as stated.
fc576fb
to
6617c78
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
Co-authored-by: Matteo Collina <matteo.collina@gmail.com>
ca645e1
to
e4a3101
Compare
|
||
assert.strictEqual(cluster.schedulingPolicy, cluster.SCHED_RR); | ||
cluster.setupPrimary({ schedulingPolicy: cluster.SCHED_NONE }); | ||
const settings = cluster.getSettings(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could be mistaken, but since getSettings()
is an internal API, does this test need the --expose-internals
flag?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this doesn't need --expose-internals
, then I imagine we're exposing getSettings()
publicly unintentionally......
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, I'm afraid getSettings() is being made public. I guess I would need to do some wizardry in lib/cluster.js to make it really internal 🤔 Should I do it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lib/cluster.js
imports lib/internal/cluster/primary.js
and re-exports it. So the options would seem to be to either re-engineer lib/cluster.js
so it re-exports a property and not the whole module--shouldn't be too hard to do but you'll need to do it in a few places because it treats lib/internal/child.js
the same way--or to find another place to export getSettings()
from (such as utils.js
but that doesn't import primary
currently). I think the first option is the way to go, but other people may have more informed opinions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not export getSettings()
from cluster
itself? And document it, marking cluster.settings
as deprecated. Exporting attributes is not a good practice in the age of import
s anyway.
b09b1d1
to
9f797a2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still needs docs for getSettings (or to not expose it) before landing
…z/node into fix/schedulingPolicy-import
Documented |
@@ -158,6 +159,10 @@ function removeHandlesForWorker(worker) { | |||
}); | |||
} | |||
|
|||
cluster.getSettings = function() { | |||
return { ...cluster.settings }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't cluster.settings
already an object literal? Why using spread on it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To copy it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And node.js does to offer helpers to shallow and/or deep clone an object to make it explicit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK using the spread is the idiomatic way of copying an object in JavaScript.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
+cluster.getSettings = function() {
cluster.prototype.settings = function() {}/Object.defineProperty(cluster, 'settings', { get: function () {}}) should works with ESM and CJS. Is it prohibited in node.js internal JS code?
You are aware that this change breaks backwards compatibility in CJS as it does not allow modifying cluster.settings, as it used to do.
The use of `Object.defineProperty()` could introduce transparent getter/setter with ESM support on existing property. And even warn for deprecation in the setter case for `setupPrimary()` usage instead.
…--
Jérôme Benoit aka fraggle
Piment Noir - https://piment-noir.org
OpenPGP Key ID : 27B535D3
Key fingerprint : B799 BBF6 8EC8 911B B8D7 CDBC C3B1 92C6 27B5 35D3
|
I'm not sure I understand your message, but I'm sure I cannot bring anything else to the table so I'm bowing out, thanks for the discussion. |
The use of Object.defineProperty() could introduce transparent getter/setter with ESM support on existing property. And even warn for deprecation in the setter case for setupPrimary() usage instead.
I'm not sure I understand your message, but I'm sure I cannot bring anything else to the table so I'm bowing out, thanks for the discussion.
cluster.settings -> cluster._settings, a non public writable property (at least non enumerable)
cluster.settings = Object.defineProperty(cluster, ’settings', {
get: function() {
return cluster._settings
},
});
If settings is set through its properties, cluster.settings.value1 = foo, cluster.settings.value1 = bar, it will work
If settings is set as an plain literal object, adding a setter will be needed:
cluster.settings = Object.defineProperty(cluster, ’settings', {
get: function() {
return cluster._settings
},
set: function(settings) {
// Sanity checks on settings type?
// Warn about deprecation?
cluster._settings = settings
},
});
If all of that is doable in internal node.js JS code, you have an ESM compatible implementation of cluster.settings without introducing cluster API changes.
Is it more clear now?
…--
Jérôme Benoit aka fraggle
Piment Noir - https://piment-noir.org
OpenPGP Key ID : 27B535D3
Key fingerprint : B799 BBF6 8EC8 911B B8D7 CDBC C3B1 92C6 27B5 35D3
|
As reported in #49240, when using ESM it is quite hard to modify
cluster.schedulingPolicy
, since the property becomes immutable onimport
and the environment variable cannot be set in code since theimport
is hoisted to the top. Setting the env variable in the console is often not desirable. The only workaround I found so far is to do a dynamicimport()
after setting the env variable in code, which is cumbersome.The solution implemented here, as suggested by @bnoordhuis in a comment, is to add
schedulingPolicy
to thecluster.settings
object:This code now works properly as expected.
@bnoordhuis also recommended that a
cluster.getSettings()
function was not desirable at this point; instead an internal method should be used. I'm not sure however how this internal method is marked, so I added it without documenting it for now.Documented in
doc/api/cluster.md
. Test added intest/known_issues/test-cluster-import-scheduling-policy.mjs
. All tests running.Possible improvements:
cluster.getSettings()
so that it can be used in ESM, wherecluster.settings
will also be immutable onimport
and the user will not be able to tell what the final settings are.cluster.schedulingPolicy
as deprecated since it is now redundant.RFC, please review.
Fixes: #49240