{"action":"created","issue":{"url":"https://api.github.com/repos/nodejs/node/issues/1239","labels_url":"https://api.github.com/repos/nodejs/node/issues/1239/labels{/name}","comments_url":"https://api.github.com/repos/nodejs/node/issues/1239/comments","events_url":"https://api.github.com/repos/nodejs/node/issues/1239/events","html_url":"https://github.com/nodejs/node/issues/1239","id":63595330,"number":1239,"title":"Breaking change: cluster connection behavior when between workers","user":{"login":"scottnonnenberg","id":443005,"avatar_url":"https://avatars.githubusercontent.com/u/443005?v=3","gravatar_id":"","url":"https://api.github.com/users/scottnonnenberg","html_url":"https://github.com/scottnonnenberg","followers_url":"https://api.github.com/users/scottnonnenberg/followers","following_url":"https://api.github.com/users/scottnonnenberg/following{/other_user}","gists_url":"https://api.github.com/users/scottnonnenberg/gists{/gist_id}","starred_url":"https://api.github.com/users/scottnonnenberg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/scottnonnenberg/subscriptions","organizations_url":"https://api.github.com/users/scottnonnenberg/orgs","repos_url":"https://api.github.com/users/scottnonnenberg/repos","events_url":"https://api.github.com/users/scottnonnenberg/events{/privacy}","received_events_url":"https://api.github.com/users/scottnonnenberg/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/nodejs/node/labels/cluster","name":"cluster","color":"f7c6c7"},{"url":"https://api.github.com/repos/nodejs/node/labels/doc","name":"doc","color":"006b75"}],"state":"closed","locked":false,"assignee":{"login":"Fishrock123","id":1093990,"avatar_url":"https://avatars.githubusercontent.com/u/1093990?v=3","gravatar_id":"","url":"https://api.github.com/users/Fishrock123","html_url":"https://github.com/Fishrock123","followers_url":"https://api.github.com/users/Fishrock123/followers","following_url":"https://api.github.com/users/Fishrock123/following{/other_user}","gists_url":"https://api.github.com/users/Fishrock123/gists{/gist_id}","starred_url":"https://api.github.com/users/Fishrock123/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Fishrock123/subscriptions","organizations_url":"https://api.github.com/users/Fishrock123/orgs","repos_url":"https://api.github.com/users/Fishrock123/repos","events_url":"https://api.github.com/users/Fishrock123/events{/privacy}","received_events_url":"https://api.github.com/users/Fishrock123/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/nodejs/node/milestones/10","html_url":"https://github.com/nodejs/node/milestones/4.0.0","labels_url":"https://api.github.com/repos/nodejs/node/milestones/10/labels","id":1232256,"number":10,"title":"4.0.0","description":"","creator":{"login":"Fishrock123","id":1093990,"avatar_url":"https://avatars.githubusercontent.com/u/1093990?v=3","gravatar_id":"","url":"https://api.github.com/users/Fishrock123","html_url":"https://github.com/Fishrock123","followers_url":"https://api.github.com/users/Fishrock123/followers","following_url":"https://api.github.com/users/Fishrock123/following{/other_user}","gists_url":"https://api.github.com/users/Fishrock123/gists{/gist_id}","starred_url":"https://api.github.com/users/Fishrock123/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Fishrock123/subscriptions","organizations_url":"https://api.github.com/users/Fishrock123/orgs","repos_url":"https://api.github.com/users/Fishrock123/repos","events_url":"https://api.github.com/users/Fishrock123/events{/privacy}","received_events_url":"https://api.github.com/users/Fishrock123/received_events","type":"User","site_admin":false},"open_issues":3,"closed_issues":27,"state":"open","created_at":"2015-07-29T19:30:25Z","updated_at":"2015-09-03T21:38:40Z","due_on":"2015-09-03T04:00:00Z","closed_at":null},"comments":8,"created_at":"2015-03-23T00:50:34Z","updated_at":"2015-09-03T22:43:50Z","closed_at":"2015-08-29T00:34:59Z","body":"[Already reported this on node 0.12](https://github.com/joyent/node/issues/10427), thought I should report it here as well.\r\n\r\nOn OSX, I've noticed a big difference between the way that connections are dealt with by a master process when there are no workers ready to take care of that incoming connection. In node `0.10.36` (and before), the connection would be held open, and a worker that hadn't been started when that request was made would have the chance to handle it. In all versions of iojs (and node `0.12.0`), incoming connections when between workers are outright refused.\r\n\r\nAt the very least, this should be documented.\r\n\r\nExample code and output on both node `0.10.36` and iojs `1.6.1` follows:\r\n\r\n```javascript\r\nvar cluster = require('cluster');\r\nvar http = require('http');\r\nvar supertest = require('supertest');\r\nvar PORT = 3000;\r\n\r\n// cluster.schedulingPolicy = cluster.SCHED_NONE;\r\n\r\nif (!cluster.isMaster) {\r\n  http.createServer(function (req, res) {\r\n    if (req.url === '/error') {\r\n      setTimeout(function() {\r\n        throw new Error('something went wrong!');\r\n      }, 500);\r\n    }\r\n    else {\r\n      res.writeHead(200, {'Content-Type': 'text/plain'});\r\n      res.end('Hello World\\n');\r\n    }\r\n  }).listen(PORT);\r\n\r\n  console.log('Worker %s running at port %s', cluster.worker.id, PORT);\r\n}\r\nelse {\r\n  var count = 0;\r\n  var request = supertest('http://localhost:' + PORT);\r\n\r\n  var hitWorker = function(count) {\r\n    console.log('%s: Worker listening! Hitting it...', count);\r\n\r\n    request\r\n      .get('/error')\r\n      .expect(200, function(err, res) {\r\n        console.log('%s: Worker taken down, now making second request', count);\r\n\r\n        request\r\n          .get('/')\r\n          .expect('Hello World\\n')\r\n          .expect(200, function(err, res) {\r\n            console.log('%s: Second request complete. Error:', count, err);\r\n          });\r\n      });\r\n  };\r\n\r\n  cluster.on('disconnect', function() {\r\n    count +=1;\r\n    if (count < 2) {\r\n      cluster.fork();\r\n    }\r\n  });\r\n\r\n  cluster.on('listening', function() {\r\n    hitWorker(count);\r\n  });\r\n\r\n  // start just one worker\r\n  cluster.fork();\r\n\r\n  var interval = setInterval(function() {\r\n    console.log('...');\r\n  }, 1000);\r\n  interval.unref();\r\n}\r\n```\r\n\r\n## output\r\n\r\niojs 1.6.1 (scheduling policy does not make a difference):\r\n```\r\nWorker 1 running at port 3000\r\n0: Worker listening! Hitting it...\r\n/Users/scottnonnenberg/Development/thehelp/cluster/test.js:12\r\n        throw new Error('something went wrong!');\r\n              ^\r\nError: something went wrong!\r\n    at null._onTimeout (/Users/scottnonnenberg/Development/thehelp/cluster/test.js:12:15)\r\n    at Timer.listOnTimeout (timers.js:88:15)\r\n0: Worker taken down, now making second request\r\n0: Second request complete. Error: { [Error: connect ECONNREFUSED 127.0.0.1:3000]\r\n  code: 'ECONNREFUSED',\r\n  errno: 'ECONNREFUSED',\r\n  syscall: 'connect',\r\n  address: '127.0.0.1',\r\n  port: 3000 }\r\nWorker 2 running at port 3000\r\n1: Worker listening! Hitting it...\r\n...\r\n/Users/scottnonnenberg/Development/thehelp/cluster/test.js:12\r\n        throw new Error('something went wrong!');\r\n              ^\r\nError: something went wrong!\r\n    at null._onTimeout (/Users/scottnonnenberg/Development/thehelp/cluster/test.js:12:15)\r\n    at Timer.listOnTimeout (timers.js:88:15)\r\n1: Worker taken down, now making second request\r\n1: Second request complete. Error: { [Error: connect ECONNREFUSED 127.0.0.1:3000]\r\n  code: 'ECONNREFUSED',\r\n  errno: 'ECONNREFUSED',\r\n  syscall: 'connect',\r\n  address: '127.0.0.1',\r\n  port: 3000 }\r\n...\r\n```\r\n\r\nnode 0.10.36:\r\n```\r\nWorker 1 running at port 3000\r\n0: Worker listening! Hitting it...\r\n\r\n/Users/scottnonnenberg/Development/thehelp/cluster/test.js:13\r\n        throw new Error('something went wrong!');\r\n              ^\r\nError: something went wrong!\r\n    at null._onTimeout (/test.js:13:15)\r\n    at Timer.listOnTimeout [as ontimeout] (timers.js:112:15)\r\n0: Worker taken down, now making second request\r\nWorker 2 running at port 3000\r\n1: Worker listening! Hitting it...\r\n0: Second request complete. Error: null\r\n...\r\n\r\n/Users/scottnonnenberg/Development/thehelp/cluster/test.js:13\r\n        throw new Error('something went wrong!');\r\n              ^\r\nError: something went wrong!\r\n    at null._onTimeout (/test.js:13:15)\r\n    at Timer.listOnTimeout [as ontimeout] (timers.js:112:15)\r\n1: Worker taken down, now making second request\r\n...\r\n...\r\n...\r\n...\r\n^C\r\n```\r\nThis version hangs, because third worker not started, and master keeps connection open. Note also that '0: second request complete' actually comes after '1: worker listening!'. This is because that initial second request actually ends up hitting the second worker. "},"comment":{"url":"https://api.github.com/repos/nodejs/node/issues/comments/137593786","html_url":"https://github.com/nodejs/node/issues/1239#issuecomment-137593786","issue_url":"https://api.github.com/repos/nodejs/node/issues/1239","id":137593786,"user":{"login":"parshap","id":332258,"avatar_url":"https://avatars.githubusercontent.com/u/332258?v=3","gravatar_id":"","url":"https://api.github.com/users/parshap","html_url":"https://github.com/parshap","followers_url":"https://api.github.com/users/parshap/followers","following_url":"https://api.github.com/users/parshap/following{/other_user}","gists_url":"https://api.github.com/users/parshap/gists{/gist_id}","starred_url":"https://api.github.com/users/parshap/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/parshap/subscriptions","organizations_url":"https://api.github.com/users/parshap/orgs","repos_url":"https://api.github.com/users/parshap/repos","events_url":"https://api.github.com/users/parshap/events{/privacy}","received_events_url":"https://api.github.com/users/parshap/received_events","type":"User","site_admin":false},"created_at":"2015-09-03T22:43:50Z","updated_at":"2015-09-03T22:43:50Z","body":"@bnoordhuis: Would it be possible to implement the previous behavior in userland?\r\n\r\nI'm thinking something along the lines of having the master process create and bind the socket, but never call accept() on it. Basically I want a `require(\"net\").createServer().listen()` that never accepts connections."}}