Skip to content

[Cluster] Primary process closes socket sporadically in linux #51578

Open
@pmadhur

Description

@pmadhur

Version

20.3.0

Platform

Linux *** 6.5.0-15-generic #15~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Jan 12 18:54:30 UTC 2 x86_64 x86_64 x86_64 GNU/Linux

Subsystem

No response

What steps will reproduce the bug?

server.js

const http = require('http');
const cluster = require('cluster');
cluster.setupPrimary({
    exec: 'worker.js',
    //execArgv: ['--inspect'],
    //inspectPort: 12000,
    args: [],
    windowsHide: true
});
const worker = cluster.fork();

const server = http.createServer((request, response) => {
    let data = '';
    request.on('data', (chunk) => {
        data += chunk.toString();
    });
    request.on('end', () => {
        if (request.method === 'POST') {
            worker.send({ type: 'request', data: JSON.parse(data) }, response.socket);
        } else {
            response.end('ok');
        }
    });
});
server.listen(3000);

worker.js

process.on('message', (message, socket) => {
    if (message.type !== 'request' || socket == null) {
        return;
    }
    const data = JSON.stringify({
        result: {
            isWorker: true,
            inputData: message.data
        }
    });
    socket.write(`HTTP/1.1 200 OK\r\n`);
    socket.write(`Server: node-worker\r\n`);
    socket.write(`Content-Length: ${Buffer.byteLength(data)}\r\n`);
    socket.write(`Content-Type: application/json\r\n`);
    socket.write(`Connection: close\r\n`);
    socket.write(`\r\n`);
    socket.end(data);
});

Start node server

node server.js

Open a browser, navigate to http://localhost:3000, open devtools, and execute the following snippet:

const totalExecutions = 100;
let numberOfExecutions = totalExecutions;
let processed = 0;
while(--numberOfExecutions >= 0) {
    doFetch();
}


function doFetch() {
    const data = {
        action: 'test',
        data: {
            foo: 'bar'
        }
    }
    const fetchOptions = {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(data)
    }
    fetch('http://localhost:3000', fetchOptions).then(response=>{
        return response.json()
    }).then((result)=>{
        onProcessed(null, result);
    }).catch(error=>{
        onProcessed(error)
    });
}

function onProcessed(error, result) {
    ++processed;
    if (error !== null) {
        console.error(error);
    }
    if (processed === totalExecutions) {
        console.log('all done');
    }
}

How often does it reproduce? Is there a required condition?

Until node v20.2.0, it works as expected, i.e., primary process never closes the socket, from v20.3.0 onwards, it does not work as expected, primary process sometimes closes the socket. In some environments, if totalExecutions in above browser snippet is changed to 7, it reproduces the error consistently.

What is the expected behavior? Why is that the expected behavior?

As in node v20.2.0 (irrelevant of whether connection is close or keep-alive), primary process should never close the socket. In worker process, socket is closed (see the example worker.js above).

What do you see instead?

Primary process closes the socket and the client (browser) gets the following message:
Screenshot 2024-01-27 171724

Additional information

Basic Hardware Info:

memory 64KiB BIOS
memory 16GiB System Memory
memory 8GiB SODIMM DDR4 Synchronous 2400 MHz (0.4 ns)
memory 8GiB SODIMM DDR4 Synchronous 2400 MHz (0.4 ns)
memory 256KiB L1 cache
memory 1MiB L2 cache
memory 8MiB L3 cache
processor Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
disk 500GB NVMe disk

Metadata

Metadata

Assignees

No one assigned

    Labels

    clusterIssues and PRs related to the cluster subsystem.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions