Skip to content

Commit 70312be

Browse files
authored
Emit and Publish Peer Connection Errors (#317)
* Emit & Publish Peer Connection Errors A zetta instance's `pubsub` can be used to react to peer client disconnect events. Currently, the _peer_client_ module will emit a "closed" event for both a socket error *and* socket close event. This means the zetta handle of 'error' events will never be called. This change adds `emit('error', err)` to the _peer_client_ module, and updates _zetta_ to publish the '_peer/disconnect' event with the `error` object as an additional property of the published data. `publish('_peer/disconnect'), {peer:peerClient, error: error});` This allows code that subscribes to the peer disconnect events to react specifically to errors. * Publish Error Updated _zetta_ module to publish '_peer/error' instead of disconnect on a peer client 'error' event. This should not cause an issues with existing code because the 'error' event was previously never emitted. * Update _peer_client_ to only emit the "error" event. #312 (comment) * Updated PR per @AdamMagaluk; changes to match _event_socket_ in: 6206dc5 * Added tests to ensure PeerClients emits the proper close event * Remove use of _peer/error and use only _peer/disconnect
1 parent 70334a8 commit 70312be

File tree

4 files changed

+67
-16
lines changed

4 files changed

+67
-16
lines changed

lib/event_socket.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,11 @@ var EventSocket = module.exports = function(ws, query, streamEnabled) {
7979
self._queryCache[topic.streamQuery] = compiled;
8080
} catch(err) {
8181
var msg = {
82-
type: 'error',
82+
type: 'error',
8383
code: 400,
8484
timestamp: new Date().getTime(),
8585
topic: msg.topic,
86-
message: err.message
86+
message: err.message
8787
}
8888
self.ws.send(JSON.stringify(msg));
8989
return;
@@ -105,7 +105,7 @@ var EventSocket = module.exports = function(ws, query, streamEnabled) {
105105

106106
this._parser.on('unsubscribe', function(msg) {
107107
self._unsubscribe(msg.subscriptionId, function(err, subscription) {
108-
if (subscription) {
108+
if (subscription) {
109109
self.emit('unsubscribe', subscription);
110110
}
111111
});
@@ -180,10 +180,15 @@ EventSocket.prototype.send = function(topic, data) {
180180

181181
// used for _peer/connect _peer/disconnect
182182
if (topic.indexOf('_peer/') === 0 && typeof tmpData.peer === 'object') {
183+
var properties = tmpData.peer.properties();
184+
if (tmpData.error) {
185+
properties.error = tmpData.error;
186+
}
187+
183188
if (this.streamEnabled) {
184-
data.data = tmpData.peer.properties();
189+
data.data = properties;
185190
} else {
186-
data = ObjectStream.format(topic, tmpData.peer.properties());
191+
data = ObjectStream.format(topic, properties);
187192
}
188193
}
189194

lib/peer_client.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function calculatePeerUrl(url, name){
2020
wsUrl = wsUrl + peerPath;
2121
} else {
2222
wsUrl = wsUrl.slice(0, wsUrl.length - 1) + peerPath;
23-
}
23+
}
2424
return wsUrl;
2525
}
2626

@@ -45,7 +45,7 @@ var PeerClient = module.exports = function(url, server) {
4545
this._zetta = server;
4646

4747
this.updateURL(url);
48-
48+
4949
// create a unique connection id peer connection, used to associate initiaion request
5050
this.connectionId = null;
5151
this.ws = new WebSocket(this._createNewUrl(), {});
@@ -57,7 +57,7 @@ util.inherits(PeerClient, EventEmitter);
5757
PeerClient.calculatePeerUrl = calculatePeerUrl;
5858

5959
PeerClient.prototype.updateURL = function(httpUrl) {
60-
var wsUrl = calculatePeerUrl(httpUrl, this._zetta._name);
60+
var wsUrl = calculatePeerUrl(httpUrl, this._zetta._name);
6161
this.url = wsUrl;
6262
};
6363

@@ -116,7 +116,7 @@ PeerClient.prototype._createSocket = function() {
116116

117117
// stop ping timer until backoff finishes
118118
self._stopPingTimeout();
119-
119+
120120
var backoff = this.generateBackoff(this.retryCount);
121121
this._backoffTimer = setTimeout(function(){
122122

@@ -128,7 +128,7 @@ PeerClient.prototype._createSocket = function() {
128128
if (self.retryCount === 0) {
129129
self.ws.on('open', function onOpen(socket) {
130130
self.checkServerReq();
131-
self.emit('connecting');
131+
self.emit('connecting');
132132
self.server.emit('connection', socket);
133133
socket.on('spdyPing', function(connection) {
134134
// reset ping timer on a spdy ping from the peer
@@ -140,7 +140,7 @@ PeerClient.prototype._createSocket = function() {
140140
self.ws.on('error', function onError(err) {
141141
self.connected = false;
142142
self.log.emit('log', 'peer-client', 'Peer connection error (' + self.url + '): ' + err);
143-
self.emit('closed');
143+
self.emit('error', err);
144144
reconnect(err);
145145
});
146146

@@ -177,7 +177,7 @@ PeerClient.prototype.checkServerReq = function() {
177177
self.retryCount = 0;
178178
self.emit('connected');
179179
self.log.emit('log', 'peer-client', 'Peer connection established (' + self.url + ')');
180-
180+
181181
res.statusCode = 200;
182182
res.end();
183183

@@ -195,7 +195,7 @@ PeerClient.prototype.generateBackoff = function(attempt) {
195195
if (attempt === 0) {
196196
return 0;
197197
}
198-
198+
199199
var random = parseInt(Math.random() * this.reconnect.maxRandomOffset);
200200
var backoff = (Math.pow(2, attempt) * this.reconnect.min);
201201
if (backoff > this.reconnect.max) {

test/test_peer_client.js

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
1+
var util = require('util');
2+
var EventEmitter = require('events').EventEmitter;
13
var PeerClient = require('../lib/peer_client');
24
var assert = require('assert');
35

46

5-
var MockServer = { _name: '1234', httpServer: { spdyServer: {}}, log: {}};
7+
var MockServer = { _name: '1234', httpServer: { spdyServer: {}}, log: {
8+
emit: function() {}
9+
}};
10+
var MockSocket = function() {
11+
EventEmitter.call(this);
12+
this.setAddress = function() {};
13+
this.start = function() {};
14+
};
15+
util.inherits(MockSocket, EventEmitter);
16+
617
var urlEndingWithSlash = 'http://cloud.zettajs.io/';
718
var urlEndingWithNoSlash = 'http://cloud.zettajs.io';
819

@@ -16,6 +27,41 @@ describe('Peer Client', function() {
1627
it('should calculate the proper url without a trailing slash', function() {
1728
var client = new PeerClient(urlEndingWithNoSlash, MockServer);
1829
assert.equal(client.url, 'ws://cloud.zettajs.io/peers/1234');
19-
});
30+
});
2031
});
32+
33+
it('should emit error when underlying ws does', function(done) {
34+
var client = new PeerClient(urlEndingWithNoSlash, MockServer);
35+
client.ws = new MockSocket();
36+
client._createSocket();
37+
client.once('error', function(err) {
38+
assert.equal(err.message, 'some message');
39+
done();
40+
});
41+
42+
client.once('closed', function() {
43+
done(new Error('Should not have emitted closed'));
44+
});
45+
46+
setTimeout(function() {
47+
client.ws.emit('error', new Error('some message'));
48+
}, 2);
49+
})
50+
51+
it('should emit closed when underlying ws does', function(done) {
52+
var client = new PeerClient(urlEndingWithNoSlash, MockServer);
53+
client.ws = new MockSocket();
54+
client._createSocket();
55+
client.once('error', function(err) {
56+
done(new Error('Should not have emitted error'));
57+
});
58+
59+
client.once('closed', function() {
60+
done();
61+
});
62+
63+
setTimeout(function() {
64+
client.ws.emit('close');
65+
}, 2);
66+
})
2167
});

zetta.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ Zetta.prototype._runPeer = function(peer) {
450450
self.peerRegistry.save(result);
451451

452452
// peer-event
453-
self.pubsub.publish('_peer/disconnect', { peer: peerClient });
453+
self.pubsub.publish('_peer/disconnect', { peer: peerClient, error: error });
454454
});
455455
});
456456

0 commit comments

Comments
 (0)