'NodeJS Websocket how to reconnect when server restarts
In Node.js I'm using websockets/ws for a WebSocket connection. Below is the code for the client. Let's say the server socket we are connecting to goes down for a minute. The close event will fire, but what is the best way to reconnect to the socket whenever the socket on the server goes down or errors?
var ws = new WebSocket('ws://localhost');
ws.on('open', function() {
console.log('socket open');
});
ws.on('error', function() {
console.log('socket error');
// how do I reconnect to the ws after x minutes here?
});
ws.on('close', function() {
console.log('socket close');
// how do I reconnect to the ws after x minutes here?
});
Solution 1:[1]
Try this:
var reconnectInterval = x * 1000 * 60;
var ws;
var connect = function(){
ws = new WebSocket('ws://localhost');
ws.on('open', function() {
console.log('socket open');
});
ws.on('error', function() {
console.log('socket error');
});
ws.on('close', function() {
console.log('socket close');
setTimeout(connect, reconnectInterval);
});
};
connect();
You get to use the original implementation without having to wrap it.
Solution 2:[2]
2018-Jan update
Reconnecting to a disconnected web socket is non-trivial, and best delegated to a library. The smallest and most actively maintained library for this purpose at the moment is reconnecting-websocket, which obsoletes joewalnes's library from the other answer. For Node.js specifically, you need to pass a constructor, such as WebSocket:
import WebSocket from 'ws';
import ReconnectingWebSocket from 'reconnecting-websocket';
const ws = new ReconnectingWebSocket('wss://some-feed.com', [], {
constructor: WebSocket,
connectionTimeout: ..., // in milliseconds
reconnectInterval: ...,
});
Solution 3:[3]
using async-await if Socket closed or any error occurred on the server the client will try to connect automatically every 5 sec forever
const ws = require('ws')
let openedSocketFlag = null
const timeInterval = 5000
const port = 3000
const url = `ws://localhost:${port}`
function connect() {
const client = new ws(url)
return new Promise((resolve, reject) => {
console.log('client try to connect...')
client.on('open', () => {
console.log('WEBSOCKET_OPEN: client connected to server at port %s', port)
openedSocketFlag = true
resolve(openedSocketFlag)
})
client.on('message', (data) => {
console.log(data.toString())
})
client.on('close', (err) => {
console.log('WEBSOCKET_CLOSE: connection closed %o', err)
openedSocketFlag = false
reject(err)
})
client.on('error', (err) => {
console.log('WEBSOCKET_ERROR: Error', new Error(err.message))
openedSocketFlag = false
reject(err)
})
})
}
async function reconnect() {
try {
await connect()
} catch (err) {
console.log('WEBSOCKET_RECONNECT: Error', new Error(err).message)
}
}
reconnect()
// repeat every 5 seconds
setInterval(() => {
if (!openedSocketFlag) {
reconnect()
}
}, timeInterval)
Solution 4:[4]
After examining @Mohamed Farouk's answer, I believe that there is merit in using a promise to signify the status of the connection. Here's an example that takes a bit from that answer, and a bit from my original:
const address = "ws://localhost";
const reconnectInterval = x * 1000 * 60;
const ws = {};
const establishSocket = address => new Promise((resolve, reject)=>{
const s = new WebSocket(address);
s.on("open", ()=>{
delete ws.reason;
ws.socket = s;
console.log('socket open');
});
s.on("error", ()=>console.log('socket error'));
s.on("close", reject);
}).catch(async (reason)=>{
ws.socket = null;
ws.reason = reason;
console.log('socket close');
await new Promise(resolve=>setTimeout(resolve, reconnectInterval));
establishSocket(address);
});
establishSocket(address);
I make no assertions as to which approach is better -- I just thought this was an interesting solution.
Solution 5:[5]
You should consider a migration to socket.io.
- It has built-in auto-reconnect functionality. And you don't have to do anything for it. It is already enabled by default.
- Surprisingly, it is compatible with older browsers, even browsers that don't support native websockets.
The code of both is very similar, but the socket.io is perhaps just a little shorter. e.g. for the server code we used to write something like this:
const WebSocketServer = require('websocket').server
const ws = new WebSocketServer({ httpServer });
ws.on('request', (request) => onConnection(request));
function onConnectionRequest(request) {
const connection = request.accept(null, request.origin);
if (!connection) return;
connection.on('message', (msg) => onMessageReceived(msg));
connection.on('close', () => onConnectionClosed());
}
function onMessage(message) {
if (message.type === 'utf8') {
const data = message.utf8Data;
const request = JSON.parse(data);
// todo use request
}
}
Socket.io code is very similar, but just a little shorter.
const io = require('socket.io')(httpServer);
io.on('connection', (socket) => onConnection(socket));
function onConnection(socket) {
socket.on('message', (msg) => onMessage(msg));
socket.on('disconnect', (reason) => onDisconnect(reason));
}
function onMessage(request) {
// todo use request
}
However, do take in mind, that you also have to rewrite the client code.
e.g. For Angular I use the ngx-socket-io plugin, which simplifies the code extremely.
Solution 6:[6]
i am using 'websocket' in my client side react/nextjs , and here is the urls for the specific package :
https://www.npmjs.com/package/websocket
https://github.com/theturtle32/WebSocket-Node
and i am using 'reconnecting-websocket' package to reconnect the client websocket to the server (which is Django channels) when the server is restarted .
and here is the official package url :
https://www.npmjs.com/package/reconnecting-websocket
and here is a simple example usage :
import { w3cwebsocket as W3CWebSocket } from "websocket";
import ReconnectingWebSocket from 'reconnecting-websocket';
//inside react component - nextjs page :
const options = {
WebSocket: W3CWebSocket, // custom WebSocket constructor
connectionTimeout: 1000,
maxRetries: 10,
};
const isServerSide = typeof window === "undefined";
let client
if(!isServerSide) {
client = new ReconnectingWebSocket(`ws://127.0.0.1:8000/ws/`,[], options);
client.binaryType = "arraybuffer";
}
useEffect(() => {
client.onopen = () => {
console.log('WebSocket Client Connected');
};
client.onerror = (error) => {
console.log("Connection Error: " , error);
};
client.onclose = (close) => {
console.log('echo-protocol Client Closed', close);
};
}, [])
this is just example and change it based on your case/requirements.
i hope this helpful
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Dan Dascalescu |
| Solution 3 | |
| Solution 4 | John Henry |
| Solution 5 | bvdb |
| Solution 6 |
