Skip to content

Commit 7a6effa

Browse files
committed
v6.6.0 - Added ability for processes to easily respond to messages over IPC via callbacks
1 parent f47dc3d commit 7a6effa

16 files changed

+348
-85
lines changed

index.js

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ var SocketCluster = function (options) {
4444
self.EVENT_WORKER_CLUSTER_EXIT = 'workerClusterExit';
4545

4646
self._pendingResponseHandlers = {};
47+
self.workerClusterMessageBuffer = [];
4748

4849
self._errorAnnotations = {
4950
'EADDRINUSE': 'Failed to bind to a port because it was already used by another process.'
@@ -125,6 +126,7 @@ SocketCluster.prototype._init = function (options) {
125126

126127
self._active = false;
127128
self.workerCluster = null;
129+
self.isWorkerClusterReady = false;
128130

129131
self._colorCodes = {
130132
red: 31,
@@ -388,9 +390,11 @@ SocketCluster.prototype._logObject = function (obj, objType, time) {
388390

389391
SocketCluster.prototype._convertValueToUnknownError = function (err, origin) {
390392
if (err && typeof err == 'object') {
391-
// If err has neither a stack or message property
392-
// then the error message will be the JSON stringified object.
393-
if (!err.message && !err.stack) {
393+
if (err.message || err.stack) {
394+
err = scErrors.hydrateError(err, true);
395+
} else {
396+
// If err has neither a stack nor a message property
397+
// then the error message will be the JSON stringified object.
394398
var errorMessage;
395399
try {
396400
errorMessage = JSON.stringify(err);
@@ -489,6 +493,8 @@ SocketCluster.prototype._workerWarningHandler = function (workerPid, warning) {
489493
SocketCluster.prototype._workerClusterReadyHandler = function () {
490494
var self = this;
491495

496+
this.isWorkerClusterReady = true;
497+
492498
if (!this._active) {
493499
if (this.options.rebootOnSignal) {
494500
process.on('SIGUSR2', function () {
@@ -512,6 +518,8 @@ SocketCluster.prototype._workerClusterReadyHandler = function () {
512518
this._logDeploymentDetails();
513519
}
514520

521+
this._flushWorkerClusterMessageBuffer();
522+
515523
var workerClusterInfo = {
516524
pid: this.workerCluster.pid,
517525
childProcess: this.workerCluster
@@ -538,6 +546,8 @@ SocketCluster.prototype._workerStartHandler = function (workerInfo, signal) {
538546
};
539547

540548
SocketCluster.prototype._handleWorkerClusterExit = function (errorCode, signal) {
549+
this.isWorkerClusterReady = false;
550+
541551
var workerClusterInfo = {
542552
pid: this.workerCluster.pid,
543553
code: errorCode,
@@ -591,6 +601,7 @@ SocketCluster.prototype._launchWorkerCluster = function () {
591601
}
592602

593603
this.workerCluster = fork(__dirname + '/lib/workercluster.js', process.argv.slice(2), execOptions);
604+
this.isWorkerClusterReady = false;
594605

595606
var workerOpts = this._cloneObject(this.options);
596607
workerOpts.paths = this._paths;
@@ -631,7 +642,7 @@ SocketCluster.prototype._launchWorkerCluster = function () {
631642
self._workerClusterErrorHandler(m.data.pid, m.data.error);
632643
}
633644
} else if (m.type == 'warning') {
634-
var warning = scErrors.hydrateError(m.data.error);
645+
var warning = scErrors.hydrateError(m.data.error, true);
635646
self._workerWarningHandler(m.data.workerPid, warning);
636647
} else if (m.type == 'ready') {
637648
self._workerClusterReadyHandler();
@@ -640,17 +651,18 @@ SocketCluster.prototype._launchWorkerCluster = function () {
640651
} else if (m.type == 'workerExit') {
641652
self._workerExitHandler(m.data);
642653
} else if (m.type == 'workerMessage') {
643-
self.emit('workerMessage', m.workerId, m.data, function (data) {
654+
self.emit('workerMessage', m.workerId, m.data, function (err, data) {
644655
if (m.cid) {
645-
self.respondToWorker(data, m.workerId, m.cid);
656+
self.respondToWorker(err, data, m.workerId, m.cid);
646657
}
647658
});
648-
} else if (m.type == 'workerResponse') {
659+
} else if (m.type == 'workerResponse' || m.type == 'workerClusterResponse') {
649660
var responseHandler = self._pendingResponseHandlers[m.rid];
650661
if (responseHandler) {
651662
clearTimeout(responseHandler.timeout);
652663
delete self._pendingResponseHandlers[m.rid];
653-
responseHandler.callback(null, m.data, m.workerId);
664+
var properError = scErrors.hydrateError(m.error, true);
665+
responseHandler.callback(properError, m.data, m.workerId);
654666
}
655667
}
656668
});
@@ -662,11 +674,15 @@ SocketCluster.prototype._launchWorkerCluster = function () {
662674
this.emit(this.EVENT_WORKER_CLUSTER_START, workerClusterInfo);
663675

664676
this.workerCluster.on('exit', this._handleWorkerClusterExit.bind(this));
677+
this.workerCluster.on('disconnect', function () {
678+
self.isWorkerClusterReady = false;
679+
});
665680
};
666681

667-
SocketCluster.prototype.respondToWorker = function (data, workerId, rid) {
682+
SocketCluster.prototype.respondToWorker = function (err, data, workerId, rid) {
668683
this.workerCluster.send({
669684
type: 'masterResponse',
685+
error: scErrors.dehydrateError(err, true),
670686
data: data,
671687
rid: rid
672688
});
@@ -727,6 +743,7 @@ SocketCluster.prototype._start = function () {
727743
expiryAccuracy: self._dataExpiryAccuracy,
728744
downgradeToUser: self.options.downgradeToUser,
729745
processTermTimeout: self.options.processTermTimeout,
746+
ipcAckTimeout: self.options.ipcAckTimeout,
730747
brokerOptions: self.options,
731748
appBrokerControllerPath: self._paths.appBrokerControllerPath,
732749
appInitControllerPath: self._paths.appInitControllerPath
@@ -750,15 +767,16 @@ SocketCluster.prototype._start = function () {
750767
self.emit(self.EVENT_BROKER_EXIT, brokerInfo);
751768
});
752769

753-
self._brokerEngineServer.on('brokerMessage', function (brokerId, data) {
754-
self.emit('brokerMessage', brokerId, data);
770+
self._brokerEngineServer.on('brokerMessage', function (brokerId, data, callback) {
771+
self.emit('brokerMessage', brokerId, data, callback);
755772
});
756773
};
757774

758775
launchBrokerEngine();
759776
};
760777

761778
SocketCluster.prototype._createIPCResponseHandler = function (callback) {
779+
var self = this;
762780
var cid = uuid.v4();
763781

764782
var responseTimeout = setTimeout(function () {
@@ -776,6 +794,15 @@ SocketCluster.prototype._createIPCResponseHandler = function (callback) {
776794
return cid;
777795
};
778796

797+
SocketCluster.prototype._flushWorkerClusterMessageBuffer = function () {
798+
var self = this;
799+
800+
this.workerClusterMessageBuffer.forEach(function (messagePacket) {
801+
self.workerCluster.send(messagePacket);
802+
});
803+
this.workerClusterMessageBuffer = [];
804+
};
805+
779806
SocketCluster.prototype.sendToWorker = function (workerId, data, callback) {
780807
var self = this;
781808

@@ -788,11 +815,15 @@ SocketCluster.prototype.sendToWorker = function (workerId, data, callback) {
788815
if (callback) {
789816
messagePacket.cid = this._createIPCResponseHandler(callback);
790817
}
791-
this.workerCluster.send(messagePacket);
818+
this.workerClusterMessageBuffer.push(messagePacket);
819+
820+
if (this.isWorkerClusterReady) {
821+
this._flushWorkerClusterMessageBuffer();
822+
}
792823
};
793824

794825
SocketCluster.prototype.sendToBroker = function (brokerId, data, callback) {
795-
this._brokerEngineServer.sendToBroker(brokerId, data);
826+
this._brokerEngineServer.sendToBroker(brokerId, data, callback);
796827
};
797828

798829
// The options object is optional and can have two boolean fields:

kubernetes/socketcluster-deployment.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ spec:
1111
spec:
1212
containers:
1313
- name: socketcluster
14-
image: socketcluster/socketcluster:v6.5.0
14+
image: socketcluster/socketcluster:v6.6.0
1515
ports:
1616
- containerPort: 8000
1717
env:

lib/scworker.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ SCWorker.prototype.getStatus = function () {
349349
};
350350

351351
SCWorker.prototype._createIPCResponseHandler = function (callback) {
352+
var self = this;
352353
var cid = uuid.v4();
353354

354355
var responseTimeout = setTimeout(function () {
@@ -371,7 +372,8 @@ SCWorker.prototype.handleMasterResponse = function (message) {
371372
if (responseHandler) {
372373
clearTimeout(responseHandler.timeout);
373374
delete this._pendingResponseHandlers[message.rid];
374-
responseHandler.callback(null, message.data);
375+
var properError = scErrors.hydrateError(message.error, true);
376+
responseHandler.callback(properError, message.data);
375377
}
376378
};
377379

@@ -388,9 +390,10 @@ SCWorker.prototype.sendToMaster = function (data, callback) {
388390
process.send(messagePacket);
389391
};
390392

391-
SCWorker.prototype.respondToMaster = function (data, rid) {
393+
SCWorker.prototype.respondToMaster = function (err, data, rid) {
392394
process.send({
393395
type: 'workerResponse',
396+
error: scErrors.dehydrateError(err, true),
394397
data: data,
395398
workerId: this.id,
396399
rid: rid
@@ -404,9 +407,9 @@ SCWorker.prototype.handleMasterEvent = function () {
404407
SCWorker.prototype.handleMasterMessage = function (message) {
405408
var self = this
406409

407-
self.emit('masterMessage', message.data, function (data) {
410+
self.emit('masterMessage', message.data, function (err, data) {
408411
if (message.cid) {
409-
self.respondToMaster(data, message.cid);
412+
self.respondToMaster(err, data, message.cid);
410413
}
411414
});
412415
};

lib/workercluster.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,16 @@ if (cluster.isMaster) {
123123
' because the worker does not exist';
124124
var notFoundError = new InvalidActionError(errorMessage);
125125
sendErrorToMaster(notFoundError);
126+
127+
if (m.cid) {
128+
process.send({
129+
type: 'workerClusterResponse',
130+
error: scErrors.dehydrateError(notFoundError, true),
131+
data: null,
132+
workerId: m.workerId,
133+
rid: m.cid
134+
});
135+
}
126136
}
127137
} else {
128138
if (m.type == 'terminate' && m.data.killClusterMaster) {

package-lock.json

Lines changed: 17 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "socketcluster",
33
"description": "SocketCluster - A Highly parallelized WebSocket server cluster to make the most of multi-core machines/instances.",
4-
"version": "6.5.0",
4+
"version": "6.6.0",
55
"homepage": "http://socketcluster.io",
66
"contributors": [
77
{
@@ -13,18 +13,14 @@
1313
"type": "git",
1414
"url": "git://github.com/SocketCluster/socketcluster.git"
1515
},
16-
"scripts":{
17-
"test":"npm run test::masterToWorkerCallback",
18-
"test::masterToWorkerCallback":"node test/internal/serverToWorker.js"
19-
},
2016
"dependencies": {
2117
"async": "2.0.0",
2218
"base64id": "0.1.0",
2319
"fs-extra": "2.0.0",
2420
"inquirer": "1.1.3",
2521
"minimist": "1.1.0",
2622
"sc-auth": "~4.1.1",
27-
"sc-broker-cluster": "~4.0.3",
23+
"sc-broker-cluster": "~4.1.0",
2824
"sc-domain": "~1.0.1",
2925
"sc-emitter": "~1.1.0",
3026
"sc-errors": "~1.3.3",

sample/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"sc-hot-reboot": "~1.0.0",
1919
"scc-broker-client": "~1.4.0",
2020
"serve-static": "1.11.2",
21-
"socketcluster": "~6.5.0",
21+
"socketcluster": "~6.6.0",
2222
"socketcluster-client": "~6.3.0"
2323
},
2424
"keywords": [

test/internal/broker.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
var fs = require('fs');
22
var http = require('http');
3-
var getTestSocketPath = require('./testsocketpath').getTestSocketPath;
3+
var getTestSocketPath = require('./test-socket-path').getTestSocketPath;
44
var util = require('util');
55

66
module.exports.run = function (broker) {

test/internal/broker2.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
2+
module.exports.run = function (broker) {
3+
console.log(' >> Broker PID:', process.pid);
4+
5+
broker.on('masterMessage', function (data, res) {
6+
console.log(`BROKER ${broker.id}::Received data from master:`, data);
7+
if (data.fail) {
8+
var err = new Error('This is an error from broker');
9+
err.name = 'MyCustomBrokerError';
10+
res(err);
11+
} else if (!data.doNothing) {
12+
res(null, {
13+
id: 1,
14+
name: 'TestName'
15+
});
16+
}
17+
});
18+
19+
var packet = {
20+
prop: 1234
21+
};
22+
23+
console.log(`BROKER ${broker.id}::Sending packet to master`);
24+
broker.sendToMaster(packet, function (err, data) {
25+
console.log(`BROKER ${broker.id}::Response error from master:`, err);
26+
console.log(`BROKER ${broker.id}::Response data packet from master:`, data);
27+
});
28+
29+
var timeoutPacket = {
30+
doNothing: true
31+
};
32+
33+
console.log(`BROKER ${broker.id}::Sending timeout-causing packet to master`);
34+
broker.sendToMaster(timeoutPacket, function (err, data) {
35+
console.log(`BROKER ${broker.id}::Timeout response error from master:`, err);
36+
console.log(`BROKER ${broker.id}::Timeout response data packet from master:`, data);
37+
});
38+
39+
var errorPacket = {
40+
fail: true
41+
};
42+
43+
console.log(`BROKER ${broker.id}::Sending error-causing packet to master`);
44+
broker.sendToMaster(errorPacket, function (err, data) {
45+
console.log(`BROKER ${broker.id}::Error response error from master:`, err);
46+
console.log(`BROKER ${broker.id}::Error response data packet from master:`, data);
47+
});
48+
49+
console.log(`BROKER ${broker.id}::Sending error-causing packet to master without callback`);
50+
broker.sendToMaster(errorPacket);
51+
};

test/internal/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ var assert = require('assert');
55
var http = require('http');
66
var util = require('util');
77
var fs = require('fs');
8-
var getTestSocketPath = require('./testsocketpath').getTestSocketPath;
8+
var getTestSocketPath = require('./test-socket-path').getTestSocketPath;
99

1010
var scServer = childProcess.fork(__dirname + '/server.js');
1111
var resultSocketPath = getTestSocketPath();

0 commit comments

Comments
 (0)