@omneedia/socketcluster
Version:
SocketCluster - A Highly parallelized WebSocket server cluster to make the most of multi-core machines/instances.
152 lines (129 loc) • 4.54 kB
JavaScript
var scClient = require('socketcluster-client');
var ClusterBrokerClient = require('./cluster-broker-client');
var packageVersion = require('./package.json').version;
var DEFAULT_PORT = 7777;
var DEFAULT_MESSAGE_CACHE_DURATION = 10000;
var DEFAULT_RETRY_DELAY = 2000;
var DEFAULT_STATE_SERVER_CONNECT_TIMEOUT = 3000;
var DEFAULT_STATE_SERVER_ACK_TIMEOUT = 2000;
var DEFAULT_RECONNECT_RANDOMNESS = 1000;
module.exports.attach = function (broker, options) {
var reconnectRandomness = options.stateServerReconnectRandomness || DEFAULT_RECONNECT_RANDOMNESS;
var authKey = options.authKey || null;
var clusterClient = new ClusterBrokerClient(broker, {
authKey: authKey,
mappingEngine: options.mappingEngine,
clientPoolSize: options.clientPoolSize,
});
if (options.noErrorLogging) {
clusterClient.on('error', (err) => {});
} else {
clusterClient.on('error', (err) => {
console.error(err);
});
}
var retryDelay = options.brokerRetryDelay || DEFAULT_RETRY_DELAY;
var scStateSocketOptions = {
hostname: options.stateServerHost, // Required option
port: options.stateServerPort || DEFAULT_PORT,
connectTimeout: options.stateServerConnectTimeout || DEFAULT_STATE_SERVER_CONNECT_TIMEOUT,
ackTimeout: options.stateServerAckTimeout || DEFAULT_STATE_SERVER_ACK_TIMEOUT,
autoReconnectOptions: {
initialDelay: retryDelay,
randomness: reconnectRandomness,
multiplier: 1,
maxDelay: retryDelay + reconnectRandomness
},
query: {
authKey,
instancePort: broker.options.port,
instanceType: 'scc-worker',
version: packageVersion
}
};
var stateSocket = scClient.connect(scStateSocketOptions);
stateSocket.on('error', (err) => {
clusterClient.emit('error', err);
});
var latestSnapshotTime = -1;
var isNewSnapshot = (updatePacket) => {
if (updatePacket.time > latestSnapshotTime) {
latestSnapshotTime = updatePacket.time;
return true;
}
return false;
};
var resetSnapshotTime = () => {
latestSnapshotTime = -1;
};
var updateBrokerMapping = (data, respond) => {
var updated = isNewSnapshot(data);
if (updated) {
clusterClient.setBrokers(data.sccBrokerURIs);
}
respond();
};
stateSocket.on('sccBrokerJoinCluster', updateBrokerMapping);
stateSocket.on('sccBrokerLeaveCluster', updateBrokerMapping);
var sccWorkerStateData = {
instanceId: broker.instanceId
};
sccWorkerStateData.instanceIp = broker.options.clusterInstanceIp;
sccWorkerStateData.instanceIpFamily = broker.options.clusterInstanceIpFamily || 'IPv4';
var emitSCCWorkerJoinCluster = () => {
stateSocket.emit('sccWorkerJoinCluster', sccWorkerStateData, (err, data) => {
if (err) {
setTimeout(emitSCCWorkerJoinCluster, retryDelay);
return;
}
resetSnapshotTime();
clusterClient.setBrokers(data.sccBrokerURIs);
});
};
stateSocket.on('connect', emitSCCWorkerJoinCluster);
var clusterMessageHandler = (channelName, packet) => {
if ((packet.sender == null || packet.sender !== broker.instanceId) && packet.messages && packet.messages.length) {
packet.messages.forEach((data) => {
broker.publish(channelName, data);
});
}
};
clusterClient.on('message', clusterMessageHandler);
broker.on('subscribe', (channelName) => {
clusterClient.subscribe(channelName);
});
broker.on('unsubscribe', (channelName) => {
clusterClient.unsubscribe(channelName);
});
var publishOutboundBuffer = {};
var publishTimeout = null;
var flushPublishOutboundBuffer = () => {
Object.keys(publishOutboundBuffer).forEach((channelName) => {
var packet = {
sender: broker.instanceId || null,
messages: publishOutboundBuffer[channelName],
};
clusterClient.publish(channelName, packet);
});
publishOutboundBuffer = {};
publishTimeout = null;
};
broker.on('publish', (channelName, data) => {
if (broker.options.pubSubBatchDuration == null) {
var packet = {
sender: broker.instanceId || null,
messages: [data],
};
clusterClient.publish(channelName, packet);
} else {
if (!publishOutboundBuffer[channelName]) {
publishOutboundBuffer[channelName] = [];
}
publishOutboundBuffer[channelName].push(data);
if (!publishTimeout) {
publishTimeout = setTimeout(flushPublishOutboundBuffer, broker.options.pubSubBatchDuration);
}
}
});
return clusterClient;
};