Skip to content

Commit d73f171

Browse files
authored
Add event at callback error in subscription (#699)
Add event at callback error in subscription. An new event type has been created.
1 parent a8e94a1 commit d73f171

File tree

5 files changed

+110
-75
lines changed

5 files changed

+110
-75
lines changed

doc/7/essentials/events/index.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,16 @@ Triggered whenever Kuzzle responds with an error
116116

117117
`@param {object} request - Request that caused the error`
118118

119+
## callbackError
120+
121+
Triggered whenever the notification handler's callback returns a rejected promise
122+
123+
**Callback arguments:**
124+
125+
`@param {Error} error - Error details`
126+
127+
`@param {Notification} notification - Notification of the handler`
128+
119129
## reconnected
120130

121131
Triggered when the current session has reconnected to Kuzzle after a disconnection, and only if `autoReconnect` is set to `true`.

src/Kuzzle.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export class Kuzzle extends KuzzleEventEmitter {
7373
* List of every events emitted by the SDK.
7474
*/
7575
public events = [
76+
'callbackError',
7677
'connected',
7778
'discarded',
7879
'disconnected',

src/core/Room.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,23 @@ class Room {
8080
data.volatile && data.volatile.sdkInstanceId === this.kuzzle.protocol.id;
8181

8282
if (this.subscribeToSelf || !fromSelf) {
83-
this.callback(data);
83+
try {
84+
const callbackResponse = this.callback(data);
85+
86+
if ( callbackResponse !== null
87+
&& typeof callbackResponse === 'object'
88+
&& typeof callbackResponse.then === 'function'
89+
&& typeof callbackResponse.catch === 'function'
90+
) {
91+
callbackResponse
92+
.catch(error => {
93+
this.kuzzle.emit('callbackError', { error, notification: data });
94+
});
95+
}
96+
}
97+
catch (error) {
98+
this.kuzzle.emit('callbackError', { error, notification: data });
99+
}
84100
}
85101
}
86102
}

test/core/room.test.js

Lines changed: 81 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
const
2-
Room = require('../../src/core/Room'),
3-
{ KuzzleEventEmitter } = require('../../src/core/KuzzleEventEmitter'),
4-
sinon = require('sinon'),
5-
should = require('should');
1+
const sinon = require('sinon');
2+
const should = require('should');
3+
4+
const Room = require('../../src/core/Room');
5+
const { KuzzleEventEmitter } = require('../../src/core/KuzzleEventEmitter');
66

77
describe('Room', () => {
8-
const
9-
eventEmitter = new KuzzleEventEmitter(),
10-
options = {opt: 'in'};
8+
const eventEmitter = new KuzzleEventEmitter();
9+
const options = {opt: 'in'};
1110

1211
let controller;
1312

@@ -22,7 +21,8 @@ describe('Room', () => {
2221
eventEmitter.removeListener(evt, listener);
2322
},
2423
tokenExpired: sinon.stub(),
25-
protocol: new KuzzleEventEmitter()
24+
protocol: new KuzzleEventEmitter(),
25+
emit: sinon.stub(),
2626
},
2727
tokenExpired: sinon.stub()
2828
};
@@ -32,9 +32,8 @@ describe('Room', () => {
3232

3333
describe('constructor', () => {
3434
it('should create a Room instance with good properties', () => {
35-
const
36-
body = {foo: 'bar'},
37-
cb = sinon.stub();
35+
const body = {foo: 'bar'};
36+
const cb = sinon.stub();
3837

3938
controller.kuzzle.autoResubscribe = 'default';
4039

@@ -85,41 +84,37 @@ describe('Room', () => {
8584
});
8685

8786
it('should handle autoResubscribe option', () => {
88-
const
89-
body = {foo: 'bar'},
90-
cb = sinon.stub();
87+
const body = {foo: 'bar'};
88+
const cb = sinon.stub();
9189

9290
controller.kuzzle.autoResubscribe = 'default';
9391

94-
const
95-
room1 = new Room(
96-
controller, 'index', 'collection', body, cb, {autoResubscribe: true}),
97-
room2 = new Room(
98-
controller, 'index', 'collection', body, cb,
99-
{autoResubscribe: false}),
100-
room3 = new Room(
101-
controller, 'index', 'collection', body, cb,
102-
{autoResubscribe: 'foobar'});
92+
const room1 = new Room(
93+
controller, 'index', 'collection', body, cb, {autoResubscribe: true});
94+
const room2 = new Room(
95+
controller, 'index', 'collection', body, cb,
96+
{autoResubscribe: false});
97+
const room3 = new Room(
98+
controller, 'index', 'collection', body, cb,
99+
{autoResubscribe: 'foobar'});
103100

104101
should(room1.autoResubscribe).be.a.Boolean().and.be.True();
105102
should(room2.autoResubscribe).be.a.Boolean().and.be.False();
106103
should(room3.autoResubscribe).be.equal('default');
107104
});
108105

109106
it('should handle subscribeToSelf option', () => {
110-
const
111-
body = {foo: 'bar'},
112-
cb = sinon.stub();
113-
114-
const
115-
room1 = new Room(
116-
controller, 'index', 'collection', body, cb, {subscribeToSelf: true}),
117-
room2 = new Room(
118-
controller, 'index', 'collection', body, cb,
119-
{subscribeToSelf: false}),
120-
room3 = new Room(
121-
controller, 'index', 'collection', body, cb,
122-
{subscribeToSelf: 'foobar'});
107+
const body = {foo: 'bar'};
108+
const cb = sinon.stub();
109+
110+
const room1 = new Room(
111+
controller, 'index', 'collection', body, cb, {subscribeToSelf: true});
112+
const room2 = new Room(
113+
controller, 'index', 'collection', body, cb,
114+
{subscribeToSelf: false});
115+
const room3 = new Room(
116+
controller, 'index', 'collection', body, cb,
117+
{subscribeToSelf: 'foobar'});
123118

124119
should(room1.subscribeToSelf).be.a.Boolean().and.be.True();
125120
should(room2.subscribeToSelf).be.a.Boolean().and.be.False();
@@ -140,17 +135,16 @@ describe('Room', () => {
140135
});
141136

142137
it('should call realtime/subscribe action with subscribe filters and return a promise that resolve the roomId and channel', () => {
143-
const
144-
opts = {
145-
opt: 'in',
146-
scope: 'in',
147-
state: 'done',
148-
users: 'all',
149-
volatile: {bar: 'foo'}
150-
},
151-
body = {foo: 'bar'},
152-
cb = sinon.stub(),
153-
room = new Room(controller, 'index', 'collection', body, cb, opts);
138+
const opts = {
139+
opt: 'in',
140+
scope: 'in',
141+
state: 'done',
142+
users: 'all',
143+
volatile: {bar: 'foo'}
144+
};
145+
const body = {foo: 'bar'};
146+
const cb = sinon.stub();
147+
const room = new Room(controller, 'index', 'collection', body, cb, opts);
154148

155149
return room.subscribe()
156150
.then(res => {
@@ -173,17 +167,16 @@ describe('Room', () => {
173167
});
174168

175169
it('should set "id" and "channel" properties', () => {
176-
const
177-
opts = {
178-
opt: 'in',
179-
scope: 'in',
180-
state: 'done',
181-
users: 'all',
182-
volatile: {bar: 'foo'}
183-
},
184-
body = {foo: 'bar'},
185-
cb = sinon.stub(),
186-
room = new Room(controller, 'index', 'collection', body, cb, opts);
170+
const opts = {
171+
opt: 'in',
172+
scope: 'in',
173+
state: 'done',
174+
users: 'all',
175+
volatile: {bar: 'foo'}
176+
};
177+
const body = {foo: 'bar'};
178+
const cb = sinon.stub();
179+
const room = new Room(controller, 'index', 'collection', body, cb, opts);
187180

188181
return room.subscribe()
189182
.then(() => {
@@ -193,17 +186,16 @@ describe('Room', () => {
193186
});
194187

195188
it('should call _channelListener while receiving data on the current channel', () => {
196-
const
197-
opts = {
198-
opt: 'in',
199-
scope: 'in',
200-
state: 'done',
201-
users: 'all',
202-
volatile: {bar: 'foo'}
203-
},
204-
body = {foo: 'bar'},
205-
cb = sinon.stub(),
206-
room = new Room(controller, 'index', 'collection', body, cb, opts);
189+
const opts = {
190+
opt: 'in',
191+
scope: 'in',
192+
state: 'done',
193+
users: 'all',
194+
volatile: {bar: 'foo'}
195+
};
196+
const body = {foo: 'bar'};
197+
const cb = sinon.stub();
198+
const room = new Room(controller, 'index', 'collection', body, cb, opts);
207199

208200
room._channelListener = sinon.stub();
209201

@@ -248,9 +240,8 @@ describe('Room', () => {
248240
});
249241

250242
describe('_channelListener', () => {
251-
let
252-
cb,
253-
room;
243+
let cb;
244+
let room;
254245

255246
beforeEach(() => {
256247
cb = sinon.stub();
@@ -333,6 +324,22 @@ describe('Room', () => {
333324
should(cb).not.be.called();
334325
should(controller.kuzzle.tokenExpired).be.called();
335326
});
336-
});
337327

328+
it('should emit an event on callback promise rejection', async () => {
329+
const data = {foo: 'bar'};
330+
const callbackError = new Error('callbackPromiseRejection');
331+
332+
cb.rejects(callbackError);
333+
334+
await room._channelListener(data);
335+
336+
should(cb)
337+
.be.calledOnce()
338+
.be.calledWith(data);
339+
340+
should(controller.kuzzle.emit)
341+
.be.calledOnce()
342+
.be.calledWithMatch('callbackError', { error: callbackError });
343+
});
344+
});
338345
});

test/kuzzle/listenersManagement.test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ describe('Kuzzle listeners management', () => {
2121

2222
it('should only listen to allowed events', () => {
2323
const knownEvents = [
24+
'callbackError',
2425
'connected',
2526
'discarded',
2627
'disconnected',

0 commit comments

Comments
 (0)