Uh oh!
There was an error while loading. Please reload this page.
cluster: sometimes debug-port value for child process can be broken - #1524
cluster: sometimes debug-port value for child process can be broken#1524Olegas wants to merge 6 commits into
Conversation
In case of long running cluster, if worker processes is restarting periodically, --debug-port value may become out of range [1024, 65535].
brendanashworth
commented
Apr 25, 2015
Is there a good way to test this? |
Olegas
commented
Apr 26, 2015
May be we can start every test with For example this in v1.x branch will fail: |
brendanashworth
commented
Apr 26, 2015
@Olegas that probably wouldn't be accepted. Could we spin off a child process with those arguments (same file) and test it that way? |
Olegas
commented
Apr 26, 2015
Ok, I'll test it this way. |
brendanashworth
commented
Apr 26, 2015
@Olegas sorry if I was vague in my last response, but it'd be spawning a new child process of the same file (kind of like this one). |
Olegas
commented
Apr 27, 2015
@brendanashworth please take a look, I've added a test case. |
Olegas
commented
Apr 27, 2015
@brendanashworth also I've noted |
rvagg
commented
Apr 27, 2015
@Olegas yes, nothing new should be going on to v1.x at this stage, we've moved to master |
There was a problem hiding this comment.
It would be a little neater to turn the number literal into a constant and use it in the range calculation above.
Aside, it's something of a (not consistently enforced) convention to name constants kFoo, i.e.:
constkDebugPortStart=1024;constkDebugPortRange=(65536-kDebugPortStart);Olegas
commented
Apr 27, 2015
@bnoordhuis Fixed |
There was a problem hiding this comment.
Style nits: line > 80 columns and missing space before brace. If you assign the arguments to a var args first, you stay under the limit.
Ditto for the line in lib/cluster.js; eyeballing it, it looks to be just over 80 columns.
bnoordhuis
commented
Apr 27, 2015
LGTM sans style errors. |
Olegas
commented
Apr 27, 2015
@bnoordhuis fixed. Splitted line in lib/cluster into 2 statements. |
There was a problem hiding this comment.
I missed it earlier today but there is a subtle change in behavior here that's also a potential bug.
Say debugPort equals 12345. That's within the legal range but your commit changes it to 12345 % 65536 + 1024 = 13369.
Worse, with debugPort == 65000, it's changed to 65000 % 65536 + 1024 = 66024 and that's not a legal port number.
There was a problem hiding this comment.
Second is not the case, cause' kDebugPortRange is not 65536, it is
There was a problem hiding this comment.
debugPort is equals to 12345 only in cluster's master. First worker created will receive 12346. After my fix it'll receive 12346 % kDebugPortRange + 1024. Yes, behaviour is changed, but I'm wondering was it documented? One have no any control on worker's debugPort value, isn't it?
There was a problem hiding this comment.
Sorry, valid point but consider debugPort == 64511: 64511 % (65536 - 1024) + 1024 = 65536.
Apropos the behavior change, I think node-inspector assumes consecutive ports.
There was a problem hiding this comment.
Ok, I'll rewrite this another way.
There was a problem hiding this comment.
Can I use generators here? :)
There was a problem hiding this comment.
@bnoordhuis 64511 % (65536 - 1024) + 1024 == 65535.
range == 64512
x % range ∈ [ 0, range )
port == x % range + 1024;
port ∈ [ 0 + 1024, range + 1024 )
port ∈ [ 1024, 64512 + 1024 )
port ∈ [ 1024, 65536 )
There was a problem hiding this comment.
Can I use generators here?
Fwiw the answer is yes if it's nicer. :)
Olegas
commented
Apr 27, 2015
@bnoordhuis I've rewrited it from scratch. I think we don't need worker ID in debug port generation. We need just monotonic sequence in allowed range here. |
mjseidel
commented
Apr 28, 2015
I was pinged to this by @cjihrig on my related PR at nodejs/node-v0.x-archive#14816; thanks, Colin. Looking forward to a resolution however it comes. I believe this commit will result in debug port collisions in some circumstances (after nextDebugPort has wrapped around and started doubly assigning the port numbers of long-lived processes). |
sam-github
commented
Apr 29, 2015
Before this, the worker would die because the debug port couldn't be listened to because its out-of-range, right? After this PR, the worker will die whenever it happens to be using a debug port that is already in use by another process? That's an improvement, because the former problem is unresolvable, whereas the second will probably be better when the next replacement worker starts: it might get an unused port. I guess there is no reasonable way to modify the debug protocol to include the target pid, and tunnel multiple debug sessions to the master's debug port, and have it then re-direct the session to an ephemeral-but-known debug port of it's worker? Since we are now maintaining a fork of the debug protocol, this might be more approachable now. I reiterate nodejs/node-v0.x-archive#14816 (comment) And in response to nodejs/node-v0.x-archive#14816 (comment), @cjihrig, I'm not certain what, if anything, would break if the worker ID for a new fork was always the lowest free. It would certainly break all kinds of unit tests (mine, also io.js I assume). Its a bit subtle figuring out when a worker ID is "unused", as well. At some points ("point" meaning "versions of node"), in master, cluster workers are removed from Despite that, I like the idea, but I wory its a breaking change: worker IDs are never recycled now, and its easy to have code that relies on this. Having an auxiliary |
Olegas
commented
Apr 29, 2015
What if we'll maintain a list of used debug ports in master and check getDebugPort() value against it? |
Olegas
commented
Apr 29, 2015
Just pick next in case of conflict |
mjseidel
commented
Apr 29, 2015
@sam-github, unless I'm missing something, I don't see how this patch will result in a worker dying upon being handed a duplicate debug port, because, as you said, which ports are in use aren't tracked. Unless dupe debug ports will reliably and mercifully cause crashes in some way I haven't tracked down, they'll run with possibly incorrect (and developer-insanity-producing) behavior. If I can get a little time I'll just check this by manually assigning the same debug port to multiple workers. @Olegas, I think that would be great, but I have two reservations: One, it's not necessarily trivial to keep track of what ports are in use and guarantee that there are no collisions. I could be wrong about that, but I feel a bit more confident in my second reservation: that it might be difficult to ensure no collisions in a timely manner, since, after all, this is overhead that will be incurred on every call to fork. |
Olegas
commented
Jun 8, 2015
TL;DRThis PR does not change any behavior. It only fixes a bug. AFAICS no need to change any docs. And it is not an imaginary bug. I hit this in production environment. Details...Before, in Node 0.10.x every process by default use port 5858 for debugger session. And all was fine, until we start using a cluster. When cluster is used, we can connect to specified worker cause' all they share same debug port. So, the fix was introduced - All went fine, until long living cluster starts to recycle it's children for some reason (some internal logic or in case of error and process crash). Debug port must be in range from 1024 to 65535. When cluster is alive for a long period of time and worker processes dying and restarting, after a while we can see a cluster can't start new worker, cause' it is trying to start new worker with debug port out of allowed range. And it can't be fixed, except a full cluster restart. With this PR, debug port numbers will be generated cyclically, starting from 5859 up to 65535 and then again from 1024 to 65535 and so on. I need not to go through 60000 debug ports to find one I need. Every worker has a PID. In my app, it is exposed as a special response header (X-Worker-ID). Knowing a pid, I can get a process and it's args. When I got args, I know the port number. I think what extending a debug protocol is not a good idea here, cause' it is far more complex task and puts a knowledge of clustering mechanisms into debugging. |
sam-github
commented
Jun 8, 2015
This a change in behaviour, the debug port is no longer base + worker ID, it now wraps. Please document. |
Olegas
commented
Jun 8, 2015
Ok. Is https://github.com/nodejs/io.js/blob/master/doc/api/debugger.markdown a right place for it? |
sam-github
commented
Jun 9, 2015
I guess so. Though I don't see any docs at all for the new debug options. Maybe add a section after advanced usage. |
mjseidel
commented
Jun 9, 2015
@sam-github fwiw, I'm regularly going through over 60,000 workers in a production environment, never attaching a debugger, and this is still a nuisance. Killing and restarting master on debug port out of bounds error is the workaround. The fact that this is a problem in environments in which the debugger (and thus debug port) will never be used makes me question the approach of attempting to retain unique debug port, since a correct implementation will be slow, and forking is already painful. That said, this PR isn't correct insofar as retaining unique debug port, but it changes crashing behavior into rarely-colliding debug port behavior, it would solve my particular problem, and I'd welcome it with open arms and a Ritter Sport. |
cjihrig
commented
Jun 10, 2015
This may sound like a crazy idea, but what if we just didn't set |
mjseidel
commented
Jun 10, 2015
@cjihrig, that's what my open PR on Node does. I don't need that flag, and I don't think failing to set it is a crazy idea. |
cjihrig
commented
Jun 10, 2015
I'm proposing either removing these lines, or putting them behind a flag. |
sam-github
commented
Jun 11, 2015
@bajtos do you have thoughts? I'm ok with not setting it unless debug was enabled by CLI, but it means that only one node process can be debugged at a time. Its an open question how many people are benefitting from debuggable cluster workers, thought. |
bajtos
commented
Jun 11, 2015
@sam-github I don't have a strong opinion, I think this is really a task of picking a lesser evil. If we decide to disable auto-increment, the we should take care to correctly handle the case where the master process is started in debug mode and cluster workers inherit the debug mode flag too. IIRC, in v0.10, running I think @cjihrig proposal (#1524 (comment)) is a good solution:
|
ChALkeR
commented
Jun 16, 2015
@Olegas Ah, I misread. You are now incrementing the supplied port number by 1, and loop only when the port number reaches 65535. I don't think that anything significantly better could be done here, though we could try to first populate the 49152-65535 port range, then fallback to 49151-1024 (decreasing). What do you think? |
cjihrig
commented
Jun 17, 2015
Worker debug ports are no longer set by default as of 309c0f4. |
brendanashworth
commented
Jun 25, 2015
Is this still an issue then? |
cjihrig
commented
Jun 25, 2015
Technically, yes. You can still run into the same issue, but you would have to do so after explicitly turning on debugging. |
Olegas
commented
Jun 25, 2015
I think we can close this now. And I plan to add some docs to cluster about this "issue" |
brendanashworth
commented
Jul 16, 2015
Okay, closing per #1524 (comment). |
Currently, each cluster worker is assigned an ever increasing --debug-port argument. A long running cluster application that does not use the debugger can run into errors related to the port range. This commit mitigates the problem by only setting the debug port if the master is started with debug arguments, or the user explicitly defines debug arguments for the worker. This commit also adds a new debug port offset counter that is only incremented when a worker is created that utilizes debugging. Fixes: nodejs/node-v0.x-archive#8159 Refs: #1524 PR-URL: #1949 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Oleg Elifantiev <oleg@elifantiev.ru>
Currently, each cluster worker is assigned an ever increasing --debug-port argument. A long running cluster application that does not use the debugger can run into errors related to the port range. This commit mitigates the problem by only setting the debug port if the master is started with debug arguments, or the user explicitly defines debug arguments for the worker. This commit also adds a new debug port offset counter that is only incremented when a worker is created that utilizes debugging. Fixes: nodejs/node-v0.x-archive#8159 Refs: #1524 PR-URL: #1949 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Oleg Elifantiev <oleg@elifantiev.ru>
Currently, each cluster worker is assigned an ever increasing --debug-port argument. A long running cluster application that does not use the debugger can run into errors related to the port range. This commit mitigates the problem by only setting the debug port if the master is started with debug arguments, or the user explicitly defines debug arguments for the worker. This commit also adds a new debug port offset counter that is only incremented when a worker is created that utilizes debugging. Fixes: nodejs/node-v0.x-archive#8159 Refs: #1524 PR-URL: #1949 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Oleg Elifantiev <oleg@elifantiev.ru>
Currently, each cluster worker is assigned an ever increasing --debug-port argument. A long running cluster application that does not use the debugger can run into errors related to the port range. This commit mitigates the problem by only setting the debug port if the master is started with debug arguments, or the user explicitly defines debug arguments for the worker. This commit also adds a new debug port offset counter that is only incremented when a worker is created that utilizes debugging. Fixes: nodejs/node-v0.x-archive#8159 Refs: #1524 PR-URL: #1949 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Oleg Elifantiev <oleg@elifantiev.ru>
Currently, each cluster worker is assigned an ever increasing --debug-port argument. A long running cluster application that does not use the debugger can run into errors related to the port range. This commit mitigates the problem by only setting the debug port if the master is started with debug arguments, or the user explicitly defines debug arguments for the worker. This commit also adds a new debug port offset counter that is only incremented when a worker is created that utilizes debugging. Fixes: nodejs/node-v0.x-archive#8159 Refs: #1524 PR-URL: #1949 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Oleg Elifantiev <oleg@elifantiev.ru>
Currently, each cluster worker is assigned an ever increasing --debug-port argument. A long running cluster application that does not use the debugger can run into errors related to the port range. This commit mitigates the problem by only setting the debug port if the master is started with debug arguments, or the user explicitly defines debug arguments for the worker. This commit also adds a new debug port offset counter that is only incremented when a worker is created that utilizes debugging. Fixes: nodejs/node-v0.x-archive#8159 Refs: #1524 PR-URL: #1949 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Oleg Elifantiev <oleg@elifantiev.ru>
Currently, each cluster worker is assigned an ever increasing --debug-port argument. A long running cluster application that does not use the debugger can run into errors related to the port range. This commit mitigates the problem by only setting the debug port if the master is started with debug arguments, or the user explicitly defines debug arguments for the worker. This commit also adds a new debug port offset counter that is only incremented when a worker is created that utilizes debugging. Fixes: nodejs/node-v0.x-archive#8159 Refs: #1524 PR-URL: #1949 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Oleg Elifantiev <oleg@elifantiev.ru>
In case of long running cluster, if worker processes is restarting
periodically, --debug-port value may become out of range [1024, 65535].