var ws = new WebSocket('ws://localhost:8080');
ws.onopen = function () {
ws.send(JSON.stringify({
.... some message the I must send when I connect ....
}));
};
ws.onmessage = function (e) {
console.log('Got a message')
console.log(e.data);
};
ws.onclose = function(e) {
console.log('socket closed try again');
}
ws.onerror = function(err) {
console.error(err)
};
When I first connect to the socket, I must first send a message to the server to authenticate myself and subscribe to channels.
The problem I have is that sometimes the socket server is unreliable and that triggers the onerror and onclose events of the 'ws' object.
Question: What is a good design pattern that would allow me, whenever the socket closes or encounters an error, wait for 10 seconds and then reconnect to the socket server (and resend the initial message to the server)
Here is what I ended up with. It works for my purposes.
function connect() {
var ws = new WebSocket('ws://localhost:8080');
ws.onopen = function() {
// subscribe to some channels
ws.send(JSON.stringify({
//.... some message the I must send when I connect ....
}));
};
ws.onmessage = function(e) {
console.log('Message:', e.data);
};
ws.onclose = function(e) {
console.log('Socket is closed. Reconnect will be attempted in 1 second.', e.reason);
setTimeout(function() {
connect();
}, 1000);
};
ws.onerror = function(err) {
console.error('Socket encountered error: ', err.message, 'Closing socket');
ws.close();
};
}
connect();
This worked for me with setInterval, because client connection can be lost.
ngOnInit(): void {
if (window.location.protocol.includes('https')) {
this.protocol = 'wss';
}
this.listenChanges();
}
listenChanges(): void {
this.socket = new WebSocket(`${this.protocol}://${window.location.host}/v1.0/your/url`);
this.socket.onmessage = (event): void => {
// your subscription stuff
this.store.dispatch(someAction);
};
this.socket.onerror = (): void => {
this.socket.close();
};
this.socket.onopen = (): void => {
clearInterval(this.timerId);
this.socket.onclose = (): void => {
this.timerId = setInterval(() => {
this.listenChanges();
}, 10000);
};
};
}
Don't forget to call clearInterval when the socket has been opened.
This isn't explicitly a react question but here is a react style answer:
TLDR: You can use setInterval to periodically check the websocket connection status and try to re-connect if the connection is closed. https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState
class TestComponent extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.connect = this.connect.bind(this);
}
componentDidMount() {
this.interval = setInterval(this.connect, 1000);
}
componentWillUnmount() {
if (this.ws) this.ws.close();
if (this.interval) clearInterval(this.interval);
}
connect() {
// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState
if (this.ws === undefined || (this.ws && this.ws.readyState === 3)) {
this.ws = new WebSocket(`ws://localhost:8080`);
this.ws.onmessage = (e) => {
console.log(JSON.parse(e.data));
};
}
}
render() {
return <div>Hey!</div>;
}
}
I found that this package https://github.com/pladaria/reconnecting-websocket can solve the reconnection issues for Websocket connections. And it has the list of configurable options, one of them is reconnectionDelayGrowFactor which determines how fast the reconnection delay grows.
using async-await if socket closed or any error occurred on the server the client will try to connect automatically every 5 sec forever
have a look to my answer
UPDATED answer:
At last, (if you are not using java) I found you'd better implement your own "ping/pong" strategy. (if you are using java, please take a look at ping/pong "action type", I don't remember very clear... )
client sent "ping" to server every 5 seconds.
server should echo a "pong" to the client once it receive "ping".
client should reconnect server if doesn't receive "pong" in 5 seconds.
Don't rely on any third party libs.
WARNING: DO NOT use these tools: (reason: they are not reliable and not stable and works in a very limited way. )
check if the network is available: https://github.com/hubspot/offline
to re-connect: https://github.com/joewalnes/reconnecting-websocket
You can use a small library if you want - ReconnectingWebSocket
Add reconnecting-websocket.js in your script tag and
It is API compatible, so when you have:
var ws = new WebSocket('ws://....');
you can replace with:
var ws = new ReconnectingWebSocket('ws://....');
Try this:
const observable = Observable.create(
(obs: Observer<MessageEvent>) => {
this.ws.onmessage = obs.next.bind(obs);
this.ws.onerror = obs.error.bind(obs);
// this.ws.onclose = obs.complete.bind(obs);
this.ws.onclose = function () {
window.location.reload()
}
return this.ws.close.bind(this.ws);
});
const observer = {
next: (data: Object) => {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data));
}
}
};
and component
getDatas() {
let url = environment.apiwebsocket
this.webSocketService.connect(url)
.subscribe(evt => {
let jsonObj = JSON.parse(evt.data)
});}
I used to have this somewhere in project:
let rc = new WebSocket(
'ws://'
+ window.location.host
+ `/ws/chat/${window.seen.pk}/`
)
now I switched to:
// ws create the websocket and returns it
function autoReconnect(ws_create){
let ws = ws_create();
function startReconnecting(){
let interval = setInterval(()=>{
console.log('trying')
ws = ws_create();
ws.onopen = () => {
console.log('stop');
ws.onclose = startReconnecting;
clearInterval(interval);
}
}, 3000);
}
ws.onclose = startReconnecting;
}
let rc;
autoReconnect(()=>{
rc = new WebSocket(
'ws://'
+ window.location.host
+ `/ws/chat/${window.seen.pk}/`
)
return rc;
});
test it by running and stop local host, it works fine. (btw I found it weird this question has been posted for a long time, but there is not a short and elegant solution)
the benefit of this method, is that it allows you to pass in an arrow function, so that you can assign variable to any outer scope.
Here's a simple version I use in my projects. It includes an incrementing wait timer for reconnects.
//wsURL - the string URL of the websocket
//waitTimer - the incrementing clock to use if no connection made
//waitSeed - used to reset the waitTimer back to default on a successful connection
//multiplier - how quickly you want the timer to grow on each unsuccessful connection attempt
const openSocket = (wsURL, waitTimer, waitSeed, multiplier) =>{
let ws = new WebSocket(wsURL);
console.log(`trying to connect to: ${ws.url}`);
ws.onopen = () => {
console.log(`connection open to: ${ws.url}`);
waitTimer = waitSeed; //reset the waitTimer if the connection is made
ws.onclose = () => {
console.log(`connection closed to: ${ws.url}`);
openSocket(ws.url, waitTimer, waitSeed, multiplier);
};
ws.onmessage = (message) => {
//do something with messge...
};
};
ws.onerror = () => {
//increaese the wait timer if not connected, but stop at a max of 2n-1 the check time
if(waitTimer < 60000) waitTimer = waitTimer * multiplier;
console.log(`error opening connection ${ws.url}, next attemp in : ${waitTimer/1000} seconds`);
setTimeout(()=>{openSocket(ws.url, waitTimer, waitSeed, multiplier)}, waitTimer);
}
}
openSocket(`ws://localhost:3000`, 1000, 1000, 2)
Alternatively you can explore socket.io. It offers this feature
on the client side you indicate reconnection: true
const io = require("socket.io-client");
const socket = io('ws://'+WS_REMOTE_ADDRESS,{
reconnection: true,
});
Related
Here a stackblitz of the problem:
https://stackblitz.com/edit/angular-ivy-jvm8pn?file=src%2Fapp%2Fapp.component.ts,src%2Fapp%2FMyWebsocketService.ts,src%2Fapp%2Fapp.component.html
How the hell do you (delete / destroy / release) a WebSocket instance???
export class MyWebsocketService {
public url;
_constructor( URL:string ) {
this.connect();
}
connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => { // blablabla }
this.ws.onmessage = () => { // blablabla }
this.ws.onclose = () => {
/////// I CANNOT for the life of me destroy that WebSocket instance from memory
/////// These are all the solutions online:
this.ws.onopen = null;
this.ws.onmessage = null;
this.ws.onclose = null;
this.ws.onerror = null;
this.ws.close();
this.ws = null;
delete this.ws;
setTimeout( _ => {
console.log('Reconnecting...');
this.connect();
}, 3000);
}
}
}
...
public websocket;
createWebsocketsServices() {
this.websocket = new MyWebsocketService('wss://whatever');
// HERE I'm changing the URL
this.websocket = new MyWebsocketService('wss://my-new-url');
////////// BUT THE FIRST WEBSET IS STILL IN MEMORY!!!!!!!
}
ngOnInit(): void {
this.createWebsocketsServices();
}
None of the solutions I found online actually resolve this issue
Understanding object creation and garbage collection of a NodeJS WebSocket server
WebSocket: How to automatically reconnect after it dies
How do you remove a native websocket handler when setting with ws.onmessage = myFunc; or ws.onopen = function(){}?
///////////// EDITED ////////////////////
"What makes you assume that the websocket is kept in memory?" A detail I forgot to mention is: in my real life application say I try to connect to 4 dummy URL and after I connect to the valid one... the ws server register 4 new connections not 1. They are still alive
My goals:
Try to connect to websocket
if can't connect try to reconnect every 3 seconds
Change the websocket url on runtime = (Destroy current ws instance + create new ws instance with new URL)
That's a hack that works for now
https://stackblitz.com/edit/angular-ivy-vjezvq?file=src/app/app.component.ts
It doesn't resolve the issue the websocket is still not released from memory but I can at least change URL
When replacing one MyWebsocketService with another one, you'll need to disconnect the former one. Otherwise the web socket stays open, continues to receive messages, and will retain in memory all the callbacks that are registered to events and the things they reference. Overwriting the websocket variable will do nothing to prevent this, it does not "destroy" the object or release its memory, it just removes one reference to the object which would allow the garbage collector to collect the object if it wasn't referenced elsewhere - but it still is referenced from the open socket.
You'll want to do
export class MyWebsocketService {
public url: string;
public ws?: WebSocket;
_constructor(url: string) {
this.url = url;
}
connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => { // blablabla }
this.ws.onmessage = () => { // blablabla }
this.ws.onclose = () => {
this.ws = null;
}
}
disconnect() {
this.ws?.close();
}
}
then
createWebsocketsServices() {
this.websocket = new MyWebsocketService('wss://whatever');
this.websocket.connect();
// HERE I'm changing the URL:
this.websocket.disconnect();
this.websocket = new MyWebsocketService('wss://my-new-url');
this.websocket.connect();
}
I'm currently following this example and I'm tring to extend upon it with my own logic.
I can get the socket to connect, but I see that there is a problem in having the client reconnect continuously - Hence why I want to have a limit on the number of retries that the client can perform.
socket.pipe(
tap((data => console.log(data))),
retryWhen((errors) =>
errors.pipe(
take(this.retryCount),
delayWhen(val =>
timer(val * 1000)
)
)
)
).subscribe()
I looked up the documentation and figured that I could use the take() operator from rxjs. However, given that I set my retryCount to 5, the following scenario can be assumed:
Client connects to socket successfully
Client disconnects from the socket
Client reconnects after 4 retries
Client disconnects
Client retries 1 times, and stops retrying (take(5) has been reached)
Is there a way, in which I can "reset" the amount of times that take() will retry? i.e. so that every time the client disconnects from the socket, it will always have 5 retries?
The retryWhen logic from your example doesn't take into account all the possible intertwined flows of connect/disconnect/reconnect. Also the reset of the reconnection attempts doesn't happen.
Beside that, you're touching the inner Observables for open and close of the webSocket directly (which is not technically wrong), while you could put all the logic and handlers inside the subject's pipe and subscription code. I've forked your example from StackBlitz and adjusted it so that any connect / disconnect and reconnect events are handled properly.
As you can see in the screenshot below, it's trying to reconnect five time before it reaches the limit and quit.
The number of reconnect retries and the delay between each trial can be tweaked via this two constants:
const maxReconnectAttempts = 5; // -1 stands for 'forever'
const reconnectAttemptDelay = 1000; // in ms
As written in the comment, if you put const maxReconnectAttempts = -1 the reconnection trials will go on forever.
You can find below the whole code taken from index.js, or here in the forked StackBlitz repo for the full reference.
import { iif, of, throwError } from 'rxjs';
import { concatMap, delay, retryWhen, tap } from 'rxjs/operators';
import { webSocket } from 'rxjs/webSocket';
// get elements
const btn1 = document.getElementById('btn1');
const btn2 = document.getElementById('btn2');
const display = document.getElementById('app');
const msg = document.getElementById('msg');
// bind click actions
btn1.onclick = connect;
btn2.onclick = disconnect;
// create a webSocketSubject
const wsUrl = 'wss://www.gasnow.org/ws/gasprice';
const maxReconnectAttempts = 5; // -1 stands for 'forever'
const reconnectAttemptDelay = 1000; // in ms
let wsSubject$;
let wsSubscription;
let disconnected = false;
let reconnectRetryCount = 0;
// display live data on view
const bindDataToView = ({ data }) => {
console.log(data);
display.innerText = Number(data.rapid);
};
// connect/subscribe to websocket url
function connect() {
if (!this.wsSubject || this.wsSubject.closed) {
wsSubject$ = webSocket(wsUrl); // create a fresh instance
console.log(`Initializing WebSocket connection to ${wsUrl}...`);
wsSubscription = wsSubject$
.pipe(
retryWhen((errors) =>
errors.pipe(
concatMap((error) =>
iif(
() =>
maxReconnectAttempts !== -1 &&
reconnectRetryCount++ >= maxReconnectAttempts,
throwError('WebSocket reconnecting retry limit exceeded!'),
of(error).pipe(
tap(() => {
disconnected = true;
console.warn('Trying to reconnect to WebSocket server...');
}),
delay(reconnectAttemptDelay)
)
)
)
)
),
tap(() => {
if (disconnected) {
disconnected = false;
reconnectRetryCount = 0;
msg.innerText = 'Streaming ...';
console.log('Successfully reconnected to the WebSocket server.');
}
})
)
.subscribe(
(data) => {
msg.innerText = 'Streaming ...';
bindDataToView(data);
},
(err) => {
reconnectRetryCount = 0;
console.error(err);
},
() => {
reconnectRetryCount = 0;
msg.innerText = 'Connection closed';
console.warn('Connection to the WebSocket server was closed!');
}
);
}
}
// close websocket connection
function disconnect() {
if (wsSubject$) {
wsSubject$.complete(); // this will trigger closingObserver and closeObserver
wsSubject$.unsubscribe();
wsSubject$ = null;
disconnected = true;
reconnectRetryCount = 0;
if (wsSubscription) {
wsSubscription.unsubscribe();
wsSubscription = null;
}
console.log('Disconnected from the WebSocket server.');
}
}
I have an API in C# (asp.net) in which i'm running this websocket server using fleck:
SocketService.start();
SocketService.server.Start(socket =>
{
socket.OnOpen = () =>
{
SocketService.Connessione(socket);
};
socket.OnClose = () =>
{
SocketService.Disconnesione(socket);
};
socket.OnMessage = message =>
{
SocketService.Messaggio(message, socket);
};
});
This is SocketService.Start():
public static void start()
{
server = new WebSocketServer($"wss://{GetLocalIPAddress()}:{"4450"}/BNS/");
}
I have tried with a simple HTML/JS page using unsecure ws and it worked fine.
Then I have tried in my main program which i need it to be run on HTTPS so when using unsecure ws chrome told me to use wss instead.
So i change my ws server to wss but then it does nothing, it gives me timeout error.
This is the JS code:
var start = function () {
var wsImpl = window.WebSocket || window.MozWebSocket;
var form = document.getElementById('sendForm');
var input = document.getElementById('sendText');
alert("Connessione...");
// create a new websocket and connect
window.ws = new wsImpl('#Percorsi.IndirizzoSocket');
alert("conn");
// when the connection is established, this method is called
ws.onopen = function () {
alert("Connessione aperta");
var openJson = {
"Id": "#Model.accountCorrente.Id",
"type": "Identificazione"
};
alert("send");
ws.send(stringify(openJson));
};
// when the connection is closed, this method is called
ws.onclose = function () {
alert("Connessione chiusa");
}
// when data is comming from the server, this metod is called
ws.onmessage = function (val) {
if (confirm("Hai ricevuto un nuovo messaggio!\nPremi ok per visualizzarlo.")) {
window.location("/Annunci/Chat/" + val);
} else { }
};
}
I can't figured out how to make it works.
Thanks in advance for your help!
It seems like you are not setting the server certificate to be used under WS over TLS (not to be confused with HTTPS which is HTTP over TLS).
If you see the example in fleck's webpage, you will realize that you have to set the Certificate:
server.Certificate = new X509Certificate2("MyCert.pfx");
So, every time I refresh the page, it seems like sockjs is creating a new connection.
I am saving every message to my mongodb on every channel.onmessage, so if I refresh my page 7 times and send a message, I would save 7 messages of the same content into my mongodb.
This is very problematic because when I retrieve those messages when I go into the chat room, to see the log, I would see bunch of duplicate messages.
I want to keep track of all connections that are 'active', and if a user tries to make another connection, I want to terminate the old one so there is only one connection listening to each message at a time.
How do I do this ?
var connections = {};
//creating the sockjs server
var chat = sockjs.createServer();
//installing handlers for sockjs server instance, with the same url as client
chat.installHandlers(server, {prefix:'/chat/private'});
var multiplexer = new multiplexServer.MultiplexServer(chat);
var configChannel = function (channelId, userId, userName){
var channel = multiplexer.registerChannel(channelId);
channel.on('connection', function (conn) {
// console.log('connection');
console.log(connections);
connections[channelId] = connections[channelId] || {};
if (connections[channelId][userId]) {
//want to close the extra connection
} else {
connections[channelId][userId] = conn;
}
// }
// if (channels[channelId][userId]) {
// conn = channels[channelId][userId];
// } else {
// channels[channelId][userId] = conn;
// }
// console.log('accessing channel! ', channels[channelId]);
conn.on('new user', function (data, message) {
console.log('new user! ', data, message);
});
// var number = connections.length;
conn.on('data', function(message) {
var messageObj = JSON.parse(message);
handler.saveMessage(messageObj.channelId, messageObj.user, messageObj.message);
console.log('received the message, ', messageObj.message);
conn.write(JSON.stringify({channelId: messageObj.channelId, user: messageObj.user, message: messageObj.message }));
});
conn.on('close', function() {
conn.write(userName + ' has disconnected');
});
});
return channel;
};
The way I resolve a problem like yours was with a Closure and Promises, I don't know if that could help you. I let you the code that help me, this is with EventBus from Vertx:
window.Events = (function NewEvents() {
var eventBusUrl = $('#eventBusUrl').val();
var eventBus = null;
return new RSVP.Promise(function(resolve, reject) {
if(!eventBus) {
eventBus = new vertx.EventBus(eventBusUrl);
eventBus.onopen = function eventBusOpened() {
console.log('Event bus online');
resolve(eventBus);
}
eventBus.onclose = function() {
eventBus = null;
};
}
});
}());
And then in other script I call it in this way:
Events.then(function(eventBus) {
console.log("registering handlers for comments");
eventBus.registerHandler(address, function(incomingMessage) {
console.log(incomingMessage);
});
});
I hope this can help you.
Regards.
var ws = new WebSocket('ws://localhost:8080');
ws.onopen = function () {
ws.send(JSON.stringify({
.... some message the I must send when I connect ....
}));
};
ws.onmessage = function (e) {
console.log('Got a message')
console.log(e.data);
};
ws.onclose = function(e) {
console.log('socket closed try again');
}
ws.onerror = function(err) {
console.error(err)
};
When I first connect to the socket, I must first send a message to the server to authenticate myself and subscribe to channels.
The problem I have is that sometimes the socket server is unreliable and that triggers the onerror and onclose events of the 'ws' object.
Question: What is a good design pattern that would allow me, whenever the socket closes or encounters an error, wait for 10 seconds and then reconnect to the socket server (and resend the initial message to the server)
Here is what I ended up with. It works for my purposes.
function connect() {
var ws = new WebSocket('ws://localhost:8080');
ws.onopen = function() {
// subscribe to some channels
ws.send(JSON.stringify({
//.... some message the I must send when I connect ....
}));
};
ws.onmessage = function(e) {
console.log('Message:', e.data);
};
ws.onclose = function(e) {
console.log('Socket is closed. Reconnect will be attempted in 1 second.', e.reason);
setTimeout(function() {
connect();
}, 1000);
};
ws.onerror = function(err) {
console.error('Socket encountered error: ', err.message, 'Closing socket');
ws.close();
};
}
connect();
This worked for me with setInterval, because client connection can be lost.
ngOnInit(): void {
if (window.location.protocol.includes('https')) {
this.protocol = 'wss';
}
this.listenChanges();
}
listenChanges(): void {
this.socket = new WebSocket(`${this.protocol}://${window.location.host}/v1.0/your/url`);
this.socket.onmessage = (event): void => {
// your subscription stuff
this.store.dispatch(someAction);
};
this.socket.onerror = (): void => {
this.socket.close();
};
this.socket.onopen = (): void => {
clearInterval(this.timerId);
this.socket.onclose = (): void => {
this.timerId = setInterval(() => {
this.listenChanges();
}, 10000);
};
};
}
Don't forget to call clearInterval when the socket has been opened.
This isn't explicitly a react question but here is a react style answer:
TLDR: You can use setInterval to periodically check the websocket connection status and try to re-connect if the connection is closed. https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState
class TestComponent extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.connect = this.connect.bind(this);
}
componentDidMount() {
this.interval = setInterval(this.connect, 1000);
}
componentWillUnmount() {
if (this.ws) this.ws.close();
if (this.interval) clearInterval(this.interval);
}
connect() {
// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState
if (this.ws === undefined || (this.ws && this.ws.readyState === 3)) {
this.ws = new WebSocket(`ws://localhost:8080`);
this.ws.onmessage = (e) => {
console.log(JSON.parse(e.data));
};
}
}
render() {
return <div>Hey!</div>;
}
}
I found that this package https://github.com/pladaria/reconnecting-websocket can solve the reconnection issues for Websocket connections. And it has the list of configurable options, one of them is reconnectionDelayGrowFactor which determines how fast the reconnection delay grows.
using async-await if socket closed or any error occurred on the server the client will try to connect automatically every 5 sec forever
have a look to my answer
UPDATED answer:
At last, (if you are not using java) I found you'd better implement your own "ping/pong" strategy. (if you are using java, please take a look at ping/pong "action type", I don't remember very clear... )
client sent "ping" to server every 5 seconds.
server should echo a "pong" to the client once it receive "ping".
client should reconnect server if doesn't receive "pong" in 5 seconds.
Don't rely on any third party libs.
WARNING: DO NOT use these tools: (reason: they are not reliable and not stable and works in a very limited way. )
check if the network is available: https://github.com/hubspot/offline
to re-connect: https://github.com/joewalnes/reconnecting-websocket
You can use a small library if you want - ReconnectingWebSocket
Add reconnecting-websocket.js in your script tag and
It is API compatible, so when you have:
var ws = new WebSocket('ws://....');
you can replace with:
var ws = new ReconnectingWebSocket('ws://....');
Try this:
const observable = Observable.create(
(obs: Observer<MessageEvent>) => {
this.ws.onmessage = obs.next.bind(obs);
this.ws.onerror = obs.error.bind(obs);
// this.ws.onclose = obs.complete.bind(obs);
this.ws.onclose = function () {
window.location.reload()
}
return this.ws.close.bind(this.ws);
});
const observer = {
next: (data: Object) => {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data));
}
}
};
and component
getDatas() {
let url = environment.apiwebsocket
this.webSocketService.connect(url)
.subscribe(evt => {
let jsonObj = JSON.parse(evt.data)
});}
I used to have this somewhere in project:
let rc = new WebSocket(
'ws://'
+ window.location.host
+ `/ws/chat/${window.seen.pk}/`
)
now I switched to:
// ws create the websocket and returns it
function autoReconnect(ws_create){
let ws = ws_create();
function startReconnecting(){
let interval = setInterval(()=>{
console.log('trying')
ws = ws_create();
ws.onopen = () => {
console.log('stop');
ws.onclose = startReconnecting;
clearInterval(interval);
}
}, 3000);
}
ws.onclose = startReconnecting;
}
let rc;
autoReconnect(()=>{
rc = new WebSocket(
'ws://'
+ window.location.host
+ `/ws/chat/${window.seen.pk}/`
)
return rc;
});
test it by running and stop local host, it works fine. (btw I found it weird this question has been posted for a long time, but there is not a short and elegant solution)
the benefit of this method, is that it allows you to pass in an arrow function, so that you can assign variable to any outer scope.
Here's a simple version I use in my projects. It includes an incrementing wait timer for reconnects.
//wsURL - the string URL of the websocket
//waitTimer - the incrementing clock to use if no connection made
//waitSeed - used to reset the waitTimer back to default on a successful connection
//multiplier - how quickly you want the timer to grow on each unsuccessful connection attempt
const openSocket = (wsURL, waitTimer, waitSeed, multiplier) =>{
let ws = new WebSocket(wsURL);
console.log(`trying to connect to: ${ws.url}`);
ws.onopen = () => {
console.log(`connection open to: ${ws.url}`);
waitTimer = waitSeed; //reset the waitTimer if the connection is made
ws.onclose = () => {
console.log(`connection closed to: ${ws.url}`);
openSocket(ws.url, waitTimer, waitSeed, multiplier);
};
ws.onmessage = (message) => {
//do something with messge...
};
};
ws.onerror = () => {
//increaese the wait timer if not connected, but stop at a max of 2n-1 the check time
if(waitTimer < 60000) waitTimer = waitTimer * multiplier;
console.log(`error opening connection ${ws.url}, next attemp in : ${waitTimer/1000} seconds`);
setTimeout(()=>{openSocket(ws.url, waitTimer, waitSeed, multiplier)}, waitTimer);
}
}
openSocket(`ws://localhost:3000`, 1000, 1000, 2)
Alternatively you can explore socket.io. It offers this feature
on the client side you indicate reconnection: true
const io = require("socket.io-client");
const socket = io('ws://'+WS_REMOTE_ADDRESS,{
reconnection: true,
});