Merge pull request #116 from medicomp/master

Compatibility with Node.js cluster module
This commit is contained in:
Brandon Nozaki Miller 2017-07-21 05:23:11 -07:00 committed by GitHub
commit 94249c24ea
8 changed files with 1392 additions and 35 deletions

View file

@ -107,6 +107,7 @@ Set these variables in the `ipc.config` scope to overwrite or set default values
retry : 500, retry : 500,
maxRetries : false, maxRetries : false,
stopRetrying : false, stopRetrying : false,
unlink : true,
interfaces : { interfaces : {
localAddress: false, localAddress: false,
localPort : false, localPort : false,
@ -136,6 +137,7 @@ Set these variables in the `ipc.config` scope to overwrite or set default values
| retry | this is the time in milliseconds a client will wait before trying to reconnect to a server if the connection is lost. This does not effect UDP sockets since they do not have a client server relationship like Unix Sockets and TCP Sockets. | | retry | this is the time in milliseconds a client will wait before trying to reconnect to a server if the connection is lost. This does not effect UDP sockets since they do not have a client server relationship like Unix Sockets and TCP Sockets. |
| maxRetries | if set, it represents the maximum number of retries after each disconnect before giving up and completely killing a specific connection | | maxRetries | if set, it represents the maximum number of retries after each disconnect before giving up and completely killing a specific connection |
| stopRetrying| Defaults to false meaning clients will continue to retry to connect to servers indefinitely at the retry interval. If set to any number the client will stop retrying when that number is exceeded after each disconnect. If set to true in real time it will immediately stop trying to connect regardless of maxRetries. If set to 0, the client will ***NOT*** try to reconnect. | | stopRetrying| Defaults to false meaning clients will continue to retry to connect to servers indefinitely at the retry interval. If set to any number the client will stop retrying when that number is exceeded after each disconnect. If set to true in real time it will immediately stop trying to connect regardless of maxRetries. If set to 0, the client will ***NOT*** try to reconnect. |
| unlink| Defaults to true meaning that the module will take care of deleting the IPC socket prior to startup. If you use `node-ipc` in a clustered environment where there will be multiple listeners on the same socket, you must set this to `false` and then take care of deleting the socket in your own code. |
| interfaces| primarily used when specifying which interface a client should connect through. see the [socket.connect documentation in the node.js api](https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener) | | interfaces| primarily used when specifying which interface a client should connect through. see the [socket.connect documentation in the node.js api](https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener) |
---- ----
@ -790,5 +792,85 @@ Writing explicit buffers, int types, doubles, floats etc. as well as big endian
``` ```
#### Server with the `cluster` Module
`node-ipc` can be used with Node.js' [cluster module](https://nodejs.org/api/cluster.html) to provide the ability to have multiple readers for a single socket. Doing so simply requires you to set the `unlink` property in the config to `false` and take care of unlinking the socket path in the master process:
##### Server
```javascript
const fs = require('fs');
const ipc=require('../../../node-ipc');
const cpuCount = require('os').cpus().length;
const cluster = require('cluster');
const socketPath = '/tmp/ipc.sock';
ipc.config.unlink = false;
if (cluster.isMaster) {
if (fs.existsSync(socketPath)) {
fs.unlinkSync(socketPath);
}
for (let i = 0; i < cpuCount; i++) {
cluster.fork();
}
}else{
ipc.serve(
socketPath,
function() {
ipc.server.on(
'currentDate',
function(data,socket) {
console.log(`pid ${process.pid} got: `, data);
}
);
}
);
ipc.server.start();
console.log(`pid ${process.pid} listening on ${socketPath}`);
}
```
##### Client
```javascript
const fs = require('fs');
const ipc = require('../../node-ipc');
const socketPath = '/tmp/ipc.sock';
//loop forever so you can see the pid of the cluster sever change in the logs
setInterval(
function() {
ipc.connectTo(
'world',
socketPath,
connecting
);
},
2000
);
function connecting(socket) {
ipc.of.world.on(
'connect',
function() {
ipc.of.world.emit(
'currentDate',
{
message: new Date().toISOString()
}
);
ipc.disconnect('world');
}
);
}
```
#### Licensed under DBAD license #### Licensed under DBAD license
See the [DBAD license](https://github.com/philsturgeon/dbad) in your language or our [licence.md](https://github.com/RIAEvangelist/node-phidget-API/blob/master/license.md) file. See the [DBAD license](https://github.com/philsturgeon/dbad) in your language or our [licence.md](https://github.com/RIAEvangelist/node-phidget-API/blob/master/license.md) file.

View file

@ -58,10 +58,14 @@ class Server extends Events{
return; return;
} }
fs.unlink( if(this.config.unlink){
this.path, fs.unlink(
startServer.bind(this) this.path,
); startServer.bind(this)
);
}else{
startServer.bind(this)();
}
} }
} }

View file

@ -28,6 +28,7 @@ class Defaults{
this.encoding='utf8'; this.encoding='utf8';
this.rawBuffer=false; this.rawBuffer=false;
this.sync=false; this.sync=false;
this.unlink=true;
this.delimiter='\f'; this.delimiter='\f';

View file

@ -0,0 +1,31 @@
const fs = require('fs');
const ipc = require('../../node-ipc');
const socketPath = '/tmp/ipc.sock';
//loop forever so you can see the pid of the cluster sever change in the logs
setInterval(
function() {
ipc.connectTo(
'world',
socketPath,
connecting
);
},
2000
);
function connecting(socket) {
ipc.of.world.on(
'connect',
function() {
ipc.of.world.emit(
'currentDate',
{
message: new Date().toISOString()
}
);
ipc.disconnect('world');
}
);
}

View file

@ -0,0 +1,32 @@
const fs = require('fs');
const ipc=require('../../../node-ipc');
const cpuCount = require('os').cpus().length;
const cluster = require('cluster');
const socketPath = '/tmp/ipc.sock';
ipc.config.unlink = false;
if (cluster.isMaster) {
if (fs.existsSync(socketPath)) {
fs.unlinkSync(socketPath);
}
for (let i = 0; i < cpuCount; i++) {
cluster.fork();
}
}else{
ipc.serve(
socketPath,
function() {
ipc.server.on(
'currentDate',
function(data,socket) {
console.log(`pid ${process.pid} got: `, data);
}
);
}
);
ipc.server.start();
console.log(`pid ${process.pid} listening on ${socketPath}`);
}

1209
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -15,10 +15,9 @@
"js-queue": "2.0.0" "js-queue": "2.0.0"
}, },
"devDependencies": { "devDependencies": {
"codacy-coverage": "1.1.3", "codacy-coverage": "2.0.0",
"jasmine": "2.4.1", "jasmine": "2.4.1",
"istanbul": "0.4.1", "istanbul": "0.4.1",
"codacy-coverage": "2.0.0",
"node-cmd": "2.0.0" "node-cmd": "2.0.0"
}, },
"scripts": { "scripts": {
@ -28,7 +27,7 @@
"coverup": "cat ./spec/coverage/lcov.info | codacy-coverage" "coverup": "cat ./spec/coverage/lcov.info | codacy-coverage"
}, },
"pre-commit": [ "pre-commit": [
"cover" "cover"
], ],
"keywords": [ "keywords": [
"IPC", "IPC",

View file

@ -61,13 +61,11 @@ class IPC{
} }
} }
function log(){ function log(...args){
if(this.config.silent){ if(this.config.silent){
return; return;
} }
const args=Array.prototype.slice.call(arguments);
for(let i=0, count=args.length; i<count; i++){ for(let i=0, count=args.length; i<count; i++){
if(typeof args[i] != 'object'){ if(typeof args[i] != 'object'){
continue; continue;
@ -111,9 +109,9 @@ function serve(path,callback){
} }
if(!path){ if(!path){
this.log( this.log(
'Server path not specified, so defaulting to'.notice, 'Server path not specified, so defaulting to',
'ipc.config.socketRoot + ipc.config.appspace + ipc.config.id'.variable, 'ipc.config.socketRoot + ipc.config.appspace + ipc.config.id',
(this.config.socketRoot+this.config.appspace+this.config.id).data this.config.socketRoot+this.config.appspace+this.config.id
); );
path=this.config.socketRoot+this.config.appspace+this.config.id; path=this.config.socketRoot+this.config.appspace+this.config.id;
} }
@ -153,9 +151,9 @@ function serveNet(host,port,UDPType,callback){
} }
if(!host){ if(!host){
this.log( this.log(
'Server host not specified, so defaulting to'.notice, 'Server host not specified, so defaulting to',
'ipc.config.networkHost'.variable, 'ipc.config.networkHost',
this.config.networkHost.data this.config.networkHost
); );
host=this.config.networkHost; host=this.config.networkHost;
} }
@ -178,8 +176,8 @@ function serveNet(host,port,UDPType,callback){
} }
if(!port){ if(!port){
this.log( this.log(
'Server port not specified, so defaulting to'.notice, 'Server port not specified, so defaulting to',
'ipc.config.networkPort'.variable, 'ipc.config.networkPort',
this.config.networkPort this.config.networkPort
); );
port=this.config.networkPort; port=this.config.networkPort;
@ -227,16 +225,16 @@ function connect(id,path,callback){
if(!id){ if(!id){
this.log( this.log(
'Service id required'.warn, 'Service id required',
'Requested service connection without specifying service id. Aborting connection attempt'.notice 'Requested service connection without specifying service id. Aborting connection attempt'
); );
return; return;
} }
if(!path){ if(!path){
this.log( this.log(
'Service path not specified, so defaulting to'.notice, 'Service path not specified, so defaulting to',
'ipc.config.socketRoot + ipc.config.appspace + id'.variable, 'ipc.config.socketRoot + ipc.config.appspace + id',
(this.config.socketRoot+this.config.appspace+id).data (this.config.socketRoot+this.config.appspace+id).data
); );
path=this.config.socketRoot+this.config.appspace+id; path=this.config.socketRoot+this.config.appspace+id;
@ -245,9 +243,9 @@ function connect(id,path,callback){
if(this.of[id]){ if(this.of[id]){
if(!this.of[id].socket.destroyed){ if(!this.of[id].socket.destroyed){
this.log( this.log(
'Already Connected to'.notice, 'Already Connected to',
id.variable, id,
'- So executing success without connection'.notice '- So executing success without connection'
); );
callback(); callback();
return; return;
@ -267,8 +265,8 @@ function connect(id,path,callback){
function connectNet(id,host,port,callback){ function connectNet(id,host,port,callback){
if(!id){ if(!id){
this.log( this.log(
'Service id required'.warn, 'Service id required',
'Requested service connection without specifying service id. Aborting connection attempt'.notice 'Requested service connection without specifying service id. Aborting connection attempt'
); );
return; return;
} }
@ -284,9 +282,9 @@ function connectNet(id,host,port,callback){
} }
if(!host){ if(!host){
this.log( this.log(
'Server host not specified, so defaulting to'.notice, 'Server host not specified, so defaulting to',
'ipc.config.networkHost'.variable, 'ipc.config.networkHost',
this.config.networkHost.data this.config.networkHost
); );
host=this.config.networkHost; host=this.config.networkHost;
} }
@ -297,8 +295,8 @@ function connectNet(id,host,port,callback){
} }
if(!port){ if(!port){
this.log( this.log(
'Server port not specified, so defaulting to'.notice, 'Server port not specified, so defaulting to',
'ipc.config.networkPort'.variable, 'ipc.config.networkPort',
this.config.networkPort this.config.networkPort
); );
port=this.config.networkPort; port=this.config.networkPort;
@ -314,10 +312,11 @@ function connectNet(id,host,port,callback){
if(this.of[id]){ if(this.of[id]){
if(!this.of[id].socket.destroyed){ if(!this.of[id].socket.destroyed){
this.log( this.log(
'Already Connected to'.notice, 'Already Connected to',
id.variable, id,
'- So executing success without connection'.notice '- So executing success without connection'
); );
callback(); callback();
return; return;