Skip to content

Investigate cluster/child_process oddity on macOS #14828

@Trott

Description

@Trott

Version: 9.0.0-pre
Platform: macOS 10.x (seen on 10.10, 10.11, and 10.12)
Subsystem: cluster child_process

A workaround/fix was introduced to test-cluster-send-handle-large-payload in #14780 so that it wouldn't time out on macOS from time to time.

It's not clear if this behavior is a bug in the test, a bug in Node.js, a bug in macOS, or simply not a bug at all.

dtruss -f output

Additional info from #14747

When this times out, the process.send() in the subprocess is getting called, but the message event on worker is not being emitted (or at least the listener is not being invoked).

If I add a callback to process.send(), it never indicates an error in this test, whether the test succeeds or times out.

Judging from #6767, process.send() may be fire-and-forget. Maybe the message gets received and maybe not.

I don't know why macOS would be more susceptible to missing the message than anything else. If this is not-a-bug behavior, I guess we can add a retry. If this is a bug... ¯(ツ)/¯

The .send() from the parent process to the subprocess never seems to fail.

Code from version of test without the fix/workaround:

'use strict';
const common = require('../common');
const assert = require('assert');
const cluster = require('cluster');
const net = require('net');

const payload = 'a'.repeat(800004);

if (cluster.isMaster) {
  const server = net.createServer();

  server.on('connection', common.mustCall((socket) => socket.unref()));

  const worker = cluster.fork();
  worker.on('message', common.mustCall(({ payload: received }, handle) => {
    assert.strictEqual(payload, received);
    assert(handle instanceof net.Socket);
    server.close();
    handle.destroy();
  }));

  server.listen(0, common.mustCall(() => {
    const port = server.address().port;
    const socket = new net.Socket();
    socket.connect(port, (err) => {
      assert.ifError(err);
      worker.send({ payload }, socket);
    });
  }));
} else {
  process.on('message', common.mustCall(({ payload: received }, handle) => {
    assert.strictEqual(payload, received);
    assert(handle instanceof net.Socket);
    process.send({ payload }, handle);

    // Prepare for a clean exit.
    process.channel.unref();
    handle.unref();
  }));
}

/cc @addaleax

Metadata

Metadata

Assignees

Labels

child_processIssues and PRs related to the child_process subsystem.clusterIssues and PRs related to the cluster subsystem.flaky-testIssues and PRs related to the tests with unstable failures on the CI.macosIssues and PRs related to the macOS platform / OSX.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions