@webex/internal-plugin-mercury 3.9.0-next.6 → 3.9.0-next.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mercury.js +319 -134
- package/dist/mercury.js.map +1 -1
- package/package.json +1 -1
- package/src/mercury.js +285 -71
- package/test/unit/spec/mercury.js +622 -1
- package/test/unit/spec/socket.js +6 -6
package/src/mercury.js
CHANGED
|
@@ -96,6 +96,80 @@ const Mercury = WebexPlugin.extend({
|
|
|
96
96
|
});
|
|
97
97
|
},
|
|
98
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Attach event listeners to a socket.
|
|
101
|
+
* @param {Socket} socket - The socket to attach listeners to
|
|
102
|
+
* @returns {void}
|
|
103
|
+
*/
|
|
104
|
+
_attachSocketEventListeners(socket) {
|
|
105
|
+
socket.on('close', (event) => this._onclose(event, socket));
|
|
106
|
+
socket.on('message', (...args) => this._onmessage(...args));
|
|
107
|
+
socket.on('pong', (...args) => this._setTimeOffset(...args));
|
|
108
|
+
socket.on('sequence-mismatch', (...args) => this._emit('sequence-mismatch', ...args));
|
|
109
|
+
socket.on('ping-pong-latency', (...args) => this._emit('ping-pong-latency', ...args));
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Handle imminent shutdown by establishing a new connection while keeping
|
|
114
|
+
* the current one alive (make-before-break).
|
|
115
|
+
* Idempotent: will no-op if already in progress.
|
|
116
|
+
* @returns {void}
|
|
117
|
+
*/
|
|
118
|
+
_handleImminentShutdown() {
|
|
119
|
+
try {
|
|
120
|
+
if (this._shutdownSwitchoverInProgress) {
|
|
121
|
+
this.logger.info(`${this.namespace}: [shutdown] switchover already in progress`);
|
|
122
|
+
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
this._shutdownSwitchoverInProgress = true;
|
|
126
|
+
this._shutdownSwitchoverId = `${Date.now()}`;
|
|
127
|
+
this.logger.info(
|
|
128
|
+
`${this.namespace}: [shutdown] switchover start, id=${this._shutdownSwitchoverId}`
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
this._connectWithBackoff(undefined, {
|
|
132
|
+
isShutdownSwitchover: true,
|
|
133
|
+
attemptOptions: {
|
|
134
|
+
isShutdownSwitchover: true,
|
|
135
|
+
onSuccess: (newSocket, webSocketUrl) => {
|
|
136
|
+
this.logger.info(
|
|
137
|
+
`${this.namespace}: [shutdown] switchover connected, url: ${webSocketUrl}`
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const oldSocket = this.socket;
|
|
141
|
+
// Atomically switch active socket reference
|
|
142
|
+
this.socket = newSocket;
|
|
143
|
+
this.connected = true; // remain connected throughout
|
|
144
|
+
|
|
145
|
+
this._emit('event:mercury_shutdown_switchover_complete', {url: webSocketUrl});
|
|
146
|
+
|
|
147
|
+
if (oldSocket) {
|
|
148
|
+
this.logger.info(
|
|
149
|
+
`${this.namespace}: [shutdown] old socket retained; server will close with 4001`
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
})
|
|
155
|
+
.then(() => {
|
|
156
|
+
this.logger.info(`${this.namespace}: [shutdown] switchover completed successfully`);
|
|
157
|
+
})
|
|
158
|
+
.catch((err) => {
|
|
159
|
+
this.logger.info(
|
|
160
|
+
`${this.namespace}: [shutdown] switchover exhausted retries; will fall back to normal reconnection`,
|
|
161
|
+
err
|
|
162
|
+
);
|
|
163
|
+
this._emit('event:mercury_shutdown_switchover_failed', {reason: err});
|
|
164
|
+
// Old socket will eventually close with 4001, triggering normal reconnection
|
|
165
|
+
});
|
|
166
|
+
} catch (e) {
|
|
167
|
+
this.logger.error(`${this.namespace}: [shutdown] error during switchover`, e);
|
|
168
|
+
this._shutdownSwitchoverInProgress = false;
|
|
169
|
+
this._emit('event:mercury_shutdown_switchover_failed', {reason: e});
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
|
|
99
173
|
/**
|
|
100
174
|
* Get the last error.
|
|
101
175
|
* @returns {any} The last error.
|
|
@@ -152,6 +226,11 @@ const Mercury = WebexPlugin.extend({
|
|
|
152
226
|
this.backoffCall.abort();
|
|
153
227
|
}
|
|
154
228
|
|
|
229
|
+
if (this._shutdownSwitchoverBackoffCall) {
|
|
230
|
+
this.logger.info(`${this.namespace}: aborting shutdown switchover`);
|
|
231
|
+
this._shutdownSwitchoverBackoffCall.abort();
|
|
232
|
+
}
|
|
233
|
+
|
|
155
234
|
if (this.socket) {
|
|
156
235
|
this.socket.removeAllListeners('message');
|
|
157
236
|
this.once('offline', resolve);
|
|
@@ -233,55 +312,63 @@ const Mercury = WebexPlugin.extend({
|
|
|
233
312
|
});
|
|
234
313
|
},
|
|
235
314
|
|
|
236
|
-
_attemptConnection(socketUrl, callback) {
|
|
315
|
+
_attemptConnection(socketUrl, callback, options = {}) {
|
|
316
|
+
const {isShutdownSwitchover = false, onSuccess = null} = options;
|
|
317
|
+
|
|
237
318
|
const socket = new Socket();
|
|
238
|
-
let
|
|
319
|
+
let newWSUrl;
|
|
239
320
|
|
|
240
|
-
|
|
241
|
-
socket.on('message', (...args) => this._onmessage(...args));
|
|
242
|
-
socket.on('pong', (...args) => this._setTimeOffset(...args));
|
|
243
|
-
socket.on('sequence-mismatch', (...args) => this._emit('sequence-mismatch', ...args));
|
|
244
|
-
socket.on('ping-pong-latency', (...args) => this._emit('ping-pong-latency', ...args));
|
|
321
|
+
this._attachSocketEventListeners(socket);
|
|
245
322
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
323
|
+
// Check appropriate backoff call based on connection type
|
|
324
|
+
if (isShutdownSwitchover && !this._shutdownSwitchoverBackoffCall) {
|
|
325
|
+
const msg = `${this.namespace}: prevent socket open when switchover backoff call no longer defined`;
|
|
326
|
+
const err = new Error(msg);
|
|
250
327
|
|
|
251
|
-
|
|
328
|
+
this.logger.info(msg);
|
|
252
329
|
|
|
253
|
-
|
|
254
|
-
|
|
330
|
+
// Call the callback with the error before rejecting
|
|
331
|
+
callback(err);
|
|
255
332
|
|
|
256
|
-
|
|
333
|
+
return Promise.reject(err);
|
|
334
|
+
}
|
|
257
335
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
pongTimeout: this.config.pongTimeout,
|
|
262
|
-
token: token.toString(),
|
|
263
|
-
trackingId: `${this.webex.sessionId}_${Date.now()}`,
|
|
264
|
-
logger: this.logger,
|
|
265
|
-
};
|
|
336
|
+
if (!isShutdownSwitchover && !this.backoffCall) {
|
|
337
|
+
const msg = `${this.namespace}: prevent socket open when backoffCall no longer defined`;
|
|
338
|
+
const err = new Error(msg);
|
|
266
339
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
340
|
+
this.logger.info(msg);
|
|
341
|
+
|
|
342
|
+
// Call the callback with the error before rejecting
|
|
343
|
+
callback(err);
|
|
272
344
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
this.socket = socket;
|
|
345
|
+
return Promise.reject(err);
|
|
346
|
+
}
|
|
276
347
|
|
|
277
|
-
|
|
348
|
+
// For shutdown switchover, don't set socket yet (make-before-break)
|
|
349
|
+
// For normal connection, set socket before opening to allow disconnect() to close it
|
|
350
|
+
if (!isShutdownSwitchover) {
|
|
351
|
+
this.socket = socket;
|
|
352
|
+
}
|
|
278
353
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
354
|
+
return this._prepareAndOpenSocket(socket, socketUrl, isShutdownSwitchover)
|
|
355
|
+
.then((webSocketUrl) => {
|
|
356
|
+
newWSUrl = webSocketUrl;
|
|
282
357
|
this.logger.info(
|
|
283
|
-
`${this.namespace}:
|
|
358
|
+
`${this.namespace}: ${
|
|
359
|
+
isShutdownSwitchover ? '[shutdown] switchover' : ''
|
|
360
|
+
} connected to mercury, success, action: connected, url: ${newWSUrl}`
|
|
284
361
|
);
|
|
362
|
+
|
|
363
|
+
// Custom success handler for shutdown switchover
|
|
364
|
+
if (onSuccess) {
|
|
365
|
+
onSuccess(socket, webSocketUrl);
|
|
366
|
+
callback();
|
|
367
|
+
|
|
368
|
+
return Promise.resolve();
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Default behavior for normal connection
|
|
285
372
|
callback();
|
|
286
373
|
|
|
287
374
|
return this.webex.internal.feature
|
|
@@ -295,6 +382,14 @@ const Mercury = WebexPlugin.extend({
|
|
|
295
382
|
});
|
|
296
383
|
})
|
|
297
384
|
.catch((reason) => {
|
|
385
|
+
// For shutdown, simpler error handling - just callback for retry
|
|
386
|
+
if (isShutdownSwitchover) {
|
|
387
|
+
this.logger.info(`${this.namespace}: [shutdown] switchover attempt failed`, reason);
|
|
388
|
+
|
|
389
|
+
return callback(reason);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Normal connection error handling (existing complex logic)
|
|
298
393
|
this.lastError = reason; // remember the last error
|
|
299
394
|
|
|
300
395
|
// Suppress connection errors that appear to be network related. This
|
|
@@ -344,10 +439,10 @@ const Mercury = WebexPlugin.extend({
|
|
|
344
439
|
.then((haMessagingEnabled) => {
|
|
345
440
|
if (haMessagingEnabled) {
|
|
346
441
|
this.logger.info(
|
|
347
|
-
`${this.namespace}: received a generic connection error, will try to connect to another datacenter. failed, action: 'failed', url: ${
|
|
442
|
+
`${this.namespace}: received a generic connection error, will try to connect to another datacenter. failed, action: 'failed', url: ${newWSUrl} error: ${reason.message}`
|
|
348
443
|
);
|
|
349
444
|
|
|
350
|
-
return this.webex.internal.services.markFailedUrl(
|
|
445
|
+
return this.webex.internal.services.markFailedUrl(newWSUrl);
|
|
351
446
|
}
|
|
352
447
|
|
|
353
448
|
return null;
|
|
@@ -363,36 +458,83 @@ const Mercury = WebexPlugin.extend({
|
|
|
363
458
|
});
|
|
364
459
|
},
|
|
365
460
|
|
|
366
|
-
|
|
461
|
+
_prepareAndOpenSocket(socket, socketUrl, isShutdownSwitchover = false) {
|
|
462
|
+
const logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : 'connection';
|
|
463
|
+
|
|
464
|
+
return Promise.all([this._prepareUrl(socketUrl), this.webex.credentials.getUserToken()]).then(
|
|
465
|
+
([webSocketUrl, token]) => {
|
|
466
|
+
let options = {
|
|
467
|
+
forceCloseDelay: this.config.forceCloseDelay,
|
|
468
|
+
pingInterval: this.config.pingInterval,
|
|
469
|
+
pongTimeout: this.config.pongTimeout,
|
|
470
|
+
token: token.toString(),
|
|
471
|
+
trackingId: `${this.webex.sessionId}_${Date.now()}`,
|
|
472
|
+
logger: this.logger,
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
if (this.webex.config.defaultMercuryOptions) {
|
|
476
|
+
const customOptionsMsg = isShutdownSwitchover
|
|
477
|
+
? 'setting custom options for switchover'
|
|
478
|
+
: 'setting custom options';
|
|
479
|
+
|
|
480
|
+
this.logger.info(`${this.namespace}: ${customOptionsMsg}`);
|
|
481
|
+
options = {...options, ...this.webex.config.defaultMercuryOptions};
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
this.logger.info(`${this.namespace}: ${logPrefix} url: ${webSocketUrl}`);
|
|
485
|
+
|
|
486
|
+
return socket.open(webSocketUrl, options).then(() => webSocketUrl);
|
|
487
|
+
}
|
|
488
|
+
);
|
|
489
|
+
},
|
|
490
|
+
|
|
491
|
+
_connectWithBackoff(webSocketUrl, context = {}) {
|
|
492
|
+
const {isShutdownSwitchover = false, attemptOptions = {}} = context;
|
|
493
|
+
|
|
367
494
|
return new Promise((resolve, reject) => {
|
|
368
495
|
// eslint gets confused about whether or not call is actually used
|
|
369
496
|
// eslint-disable-next-line prefer-const
|
|
370
497
|
let call;
|
|
371
498
|
const onComplete = (err) => {
|
|
372
|
-
|
|
499
|
+
// Clear state flags based on connection type
|
|
500
|
+
if (isShutdownSwitchover) {
|
|
501
|
+
this._shutdownSwitchoverInProgress = false;
|
|
502
|
+
this._shutdownSwitchoverBackoffCall = undefined;
|
|
503
|
+
} else {
|
|
504
|
+
this.connecting = false;
|
|
505
|
+
this.backoffCall = undefined;
|
|
506
|
+
}
|
|
373
507
|
|
|
374
|
-
this.backoffCall = undefined;
|
|
375
508
|
if (err) {
|
|
509
|
+
const msg = isShutdownSwitchover
|
|
510
|
+
? `[shutdown] switchover failed after ${call.getNumRetries()} retries`
|
|
511
|
+
: `failed to connect after ${call.getNumRetries()} retries`;
|
|
512
|
+
|
|
376
513
|
this.logger.info(
|
|
377
|
-
`${
|
|
378
|
-
this.namespace
|
|
379
|
-
}: failed to connect after ${call.getNumRetries()} retries; log statement about next retry was inaccurate; ${err}`
|
|
514
|
+
`${this.namespace}: ${msg}; log statement about next retry was inaccurate; ${err}`
|
|
380
515
|
);
|
|
381
516
|
|
|
382
517
|
return reject(err);
|
|
383
518
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
519
|
+
|
|
520
|
+
// Default success handling for normal connections
|
|
521
|
+
if (!isShutdownSwitchover) {
|
|
522
|
+
this.connected = true;
|
|
523
|
+
this.hasEverConnected = true;
|
|
524
|
+
this._emit('online');
|
|
525
|
+
this.webex.internal.newMetrics.callDiagnosticMetrics.setMercuryConnectedStatus(true);
|
|
526
|
+
}
|
|
388
527
|
|
|
389
528
|
return resolve();
|
|
390
529
|
};
|
|
391
530
|
|
|
392
531
|
// eslint-disable-next-line prefer-reflect
|
|
393
532
|
call = backoff.call((callback) => {
|
|
394
|
-
|
|
395
|
-
|
|
533
|
+
const attemptNum = call.getNumRetries();
|
|
534
|
+
const logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : 'connection';
|
|
535
|
+
|
|
536
|
+
this.logger.info(`${this.namespace}: executing ${logPrefix} attempt ${attemptNum}`);
|
|
537
|
+
this._attemptConnection(webSocketUrl, callback, attemptOptions);
|
|
396
538
|
}, onComplete);
|
|
397
539
|
|
|
398
540
|
call.setStrategy(
|
|
@@ -402,24 +544,33 @@ const Mercury = WebexPlugin.extend({
|
|
|
402
544
|
})
|
|
403
545
|
);
|
|
404
546
|
|
|
405
|
-
if (
|
|
547
|
+
if (
|
|
548
|
+
this.config.initialConnectionMaxRetries &&
|
|
549
|
+
!this.hasEverConnected &&
|
|
550
|
+
!isShutdownSwitchover
|
|
551
|
+
) {
|
|
406
552
|
call.failAfter(this.config.initialConnectionMaxRetries);
|
|
407
553
|
} else if (this.config.maxRetries) {
|
|
408
554
|
call.failAfter(this.config.maxRetries);
|
|
409
555
|
}
|
|
410
556
|
|
|
411
557
|
call.on('abort', () => {
|
|
412
|
-
|
|
413
|
-
|
|
558
|
+
const msg = isShutdownSwitchover ? 'Shutdown Switchover' : 'Connection';
|
|
559
|
+
|
|
560
|
+
this.logger.info(`${this.namespace}: ${msg} aborted`);
|
|
561
|
+
reject(new Error(`Mercury ${msg} Aborted`));
|
|
414
562
|
});
|
|
415
563
|
|
|
416
564
|
call.on('callback', (err) => {
|
|
417
565
|
if (err) {
|
|
418
566
|
const number = call.getNumRetries();
|
|
419
567
|
const delay = Math.min(call.strategy_.nextBackoffDelay_, this.config.backoffTimeMax);
|
|
568
|
+
const logPrefix = isShutdownSwitchover ? '[shutdown] switchover' : '';
|
|
420
569
|
|
|
421
570
|
this.logger.info(
|
|
422
|
-
`${this.namespace}: failed to connect; attempting retry ${
|
|
571
|
+
`${this.namespace}: ${logPrefix} failed to connect; attempting retry ${
|
|
572
|
+
number + 1
|
|
573
|
+
} in ${delay} ms`
|
|
423
574
|
);
|
|
424
575
|
/* istanbul ignore if */
|
|
425
576
|
if (process.env.NODE_ENV === 'development') {
|
|
@@ -431,9 +582,14 @@ const Mercury = WebexPlugin.extend({
|
|
|
431
582
|
this.logger.info(`${this.namespace}: connected`);
|
|
432
583
|
});
|
|
433
584
|
|
|
434
|
-
call
|
|
585
|
+
// Store backoff call reference BEFORE starting (so it's available in _attemptConnection)
|
|
586
|
+
if (isShutdownSwitchover) {
|
|
587
|
+
this._shutdownSwitchoverBackoffCall = call;
|
|
588
|
+
} else {
|
|
589
|
+
this.backoffCall = call;
|
|
590
|
+
}
|
|
435
591
|
|
|
436
|
-
|
|
592
|
+
call.start();
|
|
437
593
|
});
|
|
438
594
|
},
|
|
439
595
|
|
|
@@ -470,19 +626,42 @@ const Mercury = WebexPlugin.extend({
|
|
|
470
626
|
return handlers;
|
|
471
627
|
},
|
|
472
628
|
|
|
473
|
-
_onclose(event) {
|
|
629
|
+
_onclose(event, sourceSocket) {
|
|
474
630
|
// I don't see any way to avoid the complexity or statement count in here.
|
|
475
631
|
/* eslint complexity: [0] */
|
|
476
632
|
|
|
477
633
|
try {
|
|
634
|
+
const isActiveSocket = sourceSocket === this.socket;
|
|
478
635
|
const reason = event.reason && event.reason.toLowerCase();
|
|
479
|
-
const socketUrl = this.socket.url;
|
|
480
636
|
|
|
481
|
-
|
|
482
|
-
this.
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
637
|
+
let socketUrl;
|
|
638
|
+
if (isActiveSocket && this.socket) {
|
|
639
|
+
// Active socket closed - get URL from current socket reference
|
|
640
|
+
socketUrl = this.socket.url;
|
|
641
|
+
} else if (sourceSocket) {
|
|
642
|
+
// Old socket closed - get URL from the closed socket
|
|
643
|
+
socketUrl = sourceSocket.url;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if (isActiveSocket) {
|
|
647
|
+
// Only tear down state if the currently active socket closed
|
|
648
|
+
if (this.socket) {
|
|
649
|
+
this.socket.removeAllListeners();
|
|
650
|
+
}
|
|
651
|
+
this.unset('socket');
|
|
652
|
+
this.connected = false;
|
|
653
|
+
this._emit('offline', event);
|
|
654
|
+
this.webex.internal.newMetrics.callDiagnosticMetrics.setMercuryConnectedStatus(false);
|
|
655
|
+
} else {
|
|
656
|
+
// Old socket closed; do not flip connection state
|
|
657
|
+
this.logger.info(
|
|
658
|
+
`${this.namespace}: [shutdown] non-active socket closed, code=${event.code}`
|
|
659
|
+
);
|
|
660
|
+
// Clean up listeners from old socket now that it's closed
|
|
661
|
+
if (sourceSocket) {
|
|
662
|
+
sourceSocket.removeAllListeners();
|
|
663
|
+
}
|
|
664
|
+
}
|
|
486
665
|
|
|
487
666
|
switch (event.code) {
|
|
488
667
|
case 1003:
|
|
@@ -490,20 +669,42 @@ const Mercury = WebexPlugin.extend({
|
|
|
490
669
|
this.logger.info(
|
|
491
670
|
`${this.namespace}: Mercury service rejected last message; will not reconnect: ${event.reason}`
|
|
492
671
|
);
|
|
493
|
-
this._emit('offline.permanent', event);
|
|
672
|
+
if (isActiveSocket) this._emit('offline.permanent', event);
|
|
494
673
|
break;
|
|
495
674
|
case 4000:
|
|
496
675
|
// metric: disconnect
|
|
497
676
|
this.logger.info(`${this.namespace}: socket replaced; will not reconnect`);
|
|
498
|
-
this._emit('offline.replaced', event);
|
|
677
|
+
if (isActiveSocket) this._emit('offline.replaced', event);
|
|
678
|
+
// If not active, nothing to do
|
|
679
|
+
break;
|
|
680
|
+
case 4001:
|
|
681
|
+
// replaced during shutdown
|
|
682
|
+
if (isActiveSocket) {
|
|
683
|
+
// Server closed active socket with 4001, meaning it expected this connection
|
|
684
|
+
// to be replaced, but the switchover in _handleImminentShutdown failed.
|
|
685
|
+
// This is a permanent failure - do not reconnect.
|
|
686
|
+
this.logger.warn(
|
|
687
|
+
`${this.namespace}: active socket closed with 4001; shutdown switchover failed`
|
|
688
|
+
);
|
|
689
|
+
this._emit('offline.permanent', event);
|
|
690
|
+
} else {
|
|
691
|
+
// Expected: old socket closed after successful switchover
|
|
692
|
+
this.logger.info(
|
|
693
|
+
`${this.namespace}: old socket closed with 4001 (replaced during shutdown); no reconnect needed`
|
|
694
|
+
);
|
|
695
|
+
this._emit('offline.replaced', event);
|
|
696
|
+
}
|
|
499
697
|
break;
|
|
500
698
|
case 1001:
|
|
501
699
|
case 1005:
|
|
502
700
|
case 1006:
|
|
503
701
|
case 1011:
|
|
504
702
|
this.logger.info(`${this.namespace}: socket disconnected; reconnecting`);
|
|
505
|
-
|
|
506
|
-
|
|
703
|
+
if (isActiveSocket) {
|
|
704
|
+
this._emit('offline.transient', event);
|
|
705
|
+
this.logger.info(`${this.namespace}: [shutdown] reconnecting active socket to recover`);
|
|
706
|
+
this._reconnect(socketUrl);
|
|
707
|
+
}
|
|
507
708
|
// metric: disconnect
|
|
508
709
|
// if (code == 1011 && reason !== ping error) metric: unexpected disconnect
|
|
509
710
|
break;
|
|
@@ -511,15 +712,18 @@ const Mercury = WebexPlugin.extend({
|
|
|
511
712
|
case 3050: // 3050 indicates logout form of closure, default to old behavior, use config reason defined by consumer to proceed with the permanent block
|
|
512
713
|
if (normalReconnectReasons.includes(reason)) {
|
|
513
714
|
this.logger.info(`${this.namespace}: socket disconnected; reconnecting`);
|
|
514
|
-
|
|
515
|
-
|
|
715
|
+
if (isActiveSocket) {
|
|
716
|
+
this._emit('offline.transient', event);
|
|
717
|
+
this.logger.info(`${this.namespace}: [shutdown] reconnecting due to normal close`);
|
|
718
|
+
this._reconnect(socketUrl);
|
|
719
|
+
}
|
|
516
720
|
// metric: disconnect
|
|
517
721
|
// if (reason === done forced) metric: force closure
|
|
518
722
|
} else {
|
|
519
723
|
this.logger.info(
|
|
520
724
|
`${this.namespace}: socket disconnected; will not reconnect: ${event.reason}`
|
|
521
725
|
);
|
|
522
|
-
this._emit('offline.permanent', event);
|
|
726
|
+
if (isActiveSocket) this._emit('offline.permanent', event);
|
|
523
727
|
}
|
|
524
728
|
break;
|
|
525
729
|
default:
|
|
@@ -527,7 +731,7 @@ const Mercury = WebexPlugin.extend({
|
|
|
527
731
|
`${this.namespace}: socket disconnected unexpectedly; will not reconnect`
|
|
528
732
|
);
|
|
529
733
|
// unexpected disconnect
|
|
530
|
-
this._emit('offline.permanent', event);
|
|
734
|
+
if (isActiveSocket) this._emit('offline.permanent', event);
|
|
531
735
|
}
|
|
532
736
|
} catch (error) {
|
|
533
737
|
this.logger.error(`${this.namespace}: error occurred in close handler`, error);
|
|
@@ -542,6 +746,16 @@ const Mercury = WebexPlugin.extend({
|
|
|
542
746
|
this.logger.debug(`${this.namespace}: message envelope: `, envelope);
|
|
543
747
|
}
|
|
544
748
|
|
|
749
|
+
// Handle shutdown message shape: { type: 'shutdown' }
|
|
750
|
+
if (envelope && envelope.type === 'shutdown') {
|
|
751
|
+
this.logger.info(`${this.namespace}: [shutdown] imminent shutdown message received`);
|
|
752
|
+
this._emit('event:mercury_shutdown_imminent', envelope);
|
|
753
|
+
|
|
754
|
+
this._handleImminentShutdown();
|
|
755
|
+
|
|
756
|
+
return Promise.resolve();
|
|
757
|
+
}
|
|
758
|
+
|
|
545
759
|
const {data} = envelope;
|
|
546
760
|
|
|
547
761
|
this._applyOverrides(data);
|