Skip to content

Commit f437cd3

Browse files
committed
feat(core): Harden WebSocket connection with configurable backoff and auto-reconnect (#8177)
- Added 'backoffStrategy' to static config for global/instance customization - Replaced setTimeout with 'await me.timeout()' for robust lifecycle cleanup - Added exponential backoff (capped at 30s) to 'attemptReconnect' - Implemented state reset (reconnectAttempts=0) on successful 'onOpen' - Added auto-reconnect logic to 'onClose' for abnormal closures - Added 'reconnecting' and 'reconnect_failed' events
1 parent 21b8247 commit f437cd3

1 file changed

Lines changed: 36 additions & 8 deletions

File tree

src/data/connection/WebSocket.mjs

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ class Socket extends Base {
2626
* @protected
2727
*/
2828
ntype: 'socket-connection',
29+
/**
30+
* @member {Function} backoffStrategy=attempt=>Math.min(1000*Math.pow(2,attempt-1),30000)
31+
*/
32+
backoffStrategy: attempt => Math.min(1000 * Math.pow(2, attempt - 1), 30000),
2933
/**
3034
* @member {WebSocket|null} socket_=null
3135
* @protected
@@ -74,19 +78,36 @@ class Socket extends Base {
7478
* @param {Function} callback
7579
* @param {Object} scope
7680
*/
77-
attemptReconnect(callback, scope) {
81+
async attemptReconnect(callback, scope) {
7882
let me = this;
7983

8084
me.reconnectAttempts++;
8185

8286
if (me.reconnectAttempts < me.maxReconnectAttempts) {
83-
me.createSocket();
87+
const delay = me.backoffStrategy(me.reconnectAttempts);
88+
89+
me.fire('reconnecting', {
90+
attempt : me.reconnectAttempts,
91+
maxAttempts: me.maxReconnectAttempts,
92+
delay
93+
});
94+
95+
console.log(`WebSocket reconnect attempt ${me.reconnectAttempts}/${me.maxReconnectAttempts} in ${delay}ms`);
8496

85-
callback && me.on('open', {
86-
callback,
87-
scope : scope || me,
88-
single: true
89-
})
97+
await me.timeout(delay);
98+
99+
if (!me.isDestroyed) {
100+
me.createSocket();
101+
102+
callback && me.on('open', {
103+
callback,
104+
scope : scope || me,
105+
single: true
106+
})
107+
}
108+
} else {
109+
console.error('Max reconnection attempts reached');
110+
me.fire('reconnect_failed')
90111
}
91112
}
92113

@@ -171,7 +192,13 @@ class Socket extends Base {
171192
* @param {Boolean} wasClean Indicates whether or not the connection was cleanly closed.
172193
*/
173194
onClose(event, reason, wasClean) {
174-
this.fire('close', {event, reason, wasClean})
195+
this.fire('close', {event, reason, wasClean});
196+
197+
// Auto-reconnect on abnormal closure
198+
if (!wasClean || event.code !== 1000) {
199+
console.warn('WebSocket closed abnormally, attempting reconnect...');
200+
this.attemptReconnect()
201+
}
175202
}
176203

177204
/**
@@ -200,6 +227,7 @@ class Socket extends Base {
200227
*
201228
*/
202229
onOpen() {
230+
this.reconnectAttempts = 0;
203231
this.fire('open', {scope: this})
204232
}
205233

0 commit comments

Comments
 (0)