pladaria / reconnecting-websocket

Reconnecting WebSocket. For Web, React Native, cli (Node.js)
MIT License
1.23k stars 199 forks source link

Handling of ECONNREFUSED #37

Closed Szellem closed 6 years ago

Szellem commented 7 years ago

Hi,

I'd like to start a connection before the server is up and keep retrying until the connection is finally accepted. I'm using 'ws' in node.js as the underlying ws implementation. The problem with this is the 'close' event comes before 'open' (actually no 'open' comes, only a 'close' and an 'error'), so the timeout handler is not removed and I get the following error during the second try:

RWS: init
RWS: connect
RWS: bypass properties
error:  { Error: connect ECONNREFUSED 127.0.0.1:8167
    at Object.exports._errnoException (util.js:1024:11)
    at exports._exceptionWithHostPort (util.js:1047:20)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1150:14)
  code: 'ECONNREFUSED',
  errno: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 8167 }
RWS: handleClose { shouldRetry: true }
RWS: retries count: 1
RWS: handleClose - reconnectDelay: 2940.596362061423
Connection closed:  1006
RWS: connect
RWS: bypass properties
RWS: timeout
events.js:182
      throw er; // Unhandled 'error' event
      ^

Error: closed before the connection is established
    at WebSocket.close (<project>\node_modules\ws\lib\WebSocket.js:270:28)
    at Timeout._onTimeout (<project>\node_modules\reconnecting-websocket\dist\index.js:126:16)
    at ontimeout (timers.js:469:11)
    at tryOnTimeout (timers.js:304:5)
    at Timer.listOnTimeout (timers.js:264:5)

Extract from my code:

const ReconnectingWebSocket = require('reconnecting-websocket');
const WebSocket = require('ws');
this.ws = new ReconnectingWebSocket(url, [], {constructor: WebSocket, debug: true});

this.ws.on('error', (data) => {
   console.log('error: ', data);
});

this.ws.on('close', (code, reason) => {
   console.log('Connection closed: ', code, reason);
   this.connectionStatus = 'disconnected';
});

Is there any workaround for this? Is this an issue with reconnecting-websocket or ws?

Szellem commented 7 years ago

Adding clearTimeout(connectingTimeout); to handleClose eliminated the timeout issue, now I get the following:

RWS: handleClose { shouldRetry: true }
RWS: retries count: 1
RWS: handleClose - reconnectDelay: 1740.4204180120016
Connection closed:  1006
RWS: connect
RWS: bypass properties
events.js:182
      throw er; // Unhandled 'error' event
      ^

Error: connect ECONNREFUSED 127.0.0.1:8167
    at Object.exports._errnoException (util.js:1024:11)
    at exports._exceptionWithHostPort (util.js:1047:20)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1150:14)
Szellem commented 7 years ago

This might be connected to this issue: https://github.com/websockets/ws/issues/163

Szellem commented 7 years ago

As mentioned in the linked issue, the event handlers of old ws instance are set to undefined after the connection error, so the following line removes all of them from the new instance too: https://github.com/pladaria/reconnecting-websocket/blob/31a0f01af4c96dfb1ba0c17b1124de204cd0e513/dist/index.js#L45

After commenting this block out and using addEventListener() instead of on in my code, it works with ws lib. A possible fix would be to skip assignment of undefined listeners in this block. What do you think?

pladaria commented 7 years ago

Hi,

Can you reproduce your issues using html5-websocket? I had troubles using ws directly so I created that wrapper.

Szellem commented 7 years ago

With html5-websocket it works fine. The only problem with html5-websocket is that for some reason it doesn't deliver connection close reason and code but I can live with that for now. Thank you!

jonface commented 6 years ago

@Szellem thanks for the advice, this worked for me,

"ws": "5.1.1", "reconnecting-websocket": "3.2.2",

node 9.6.1

Used ,

addEventListener() instead of on

No other changes.

pladaria commented 6 years ago

Hi, latest version doesn't requires html5-websocket and you should be able to use ws.

Give it a try. Don't hesitate to send any feedback. Thanks

sayhicoelho commented 2 years ago

Same issue here.

1000
Connection closed
Error: TIMEOUT
    at ReconnectingWebSocket._handleTimeout (<project>\node_modules\reconnecting-websocket\dist\reconnecting-websocket-cjs.js:529:42)
    at Timeout.<anonymous> (<project>\node_modules\reconnecting-websocket\dist\reconnecting-websocket-cjs.js:524:75)
    at listOnTimeout (internal/timers.js:554:17)
    at processTimers (internal/timers.js:497:7)
Connection error
events.js:292
      throw er; // Unhandled 'error' event
      ^

Error: WebSocket was closed before the connection was established
    at WebSocket.close (<project>\node_modules\ws\lib\websocket.js:285:14)
    at ReconnectingWebSocket._disconnect (<project>\node_modules\reconnecting-websocket\dist\reconnecting-websocket-cjs.js:539:22)
    at ReconnectingWebSocket._handleError (<project>\node_modules\reconnecting-websocket\dist\reconnecting-websocket-cjs.js:180:19)
    at ReconnectingWebSocket._handleTimeout (<project>\node_modules\reconnecting-websocket\dist\reconnecting-websocket-cjs.js:529:14)
    at Timeout.<anonymous> (<project>\node_modules\reconnecting-websocket\dist\reconnecting-websocket-cjs.js:524:75)
    at listOnTimeout (internal/timers.js:554:17)
    at processTimers (internal/timers.js:497:7)
Emitted 'error' event on WebSocket instance at:
    at emitErrorAndClose (<project>\node_modules\ws\lib\websocket.js:993:13)
    at processTicksAndRejections (internal/process/task_queues.js:80:21)

This is killing my application after timeout and can't try to connect again.

Any solution here?

node: v14.15.5 reconnecting-websocket: ^4.4.0 ws: ^8.7.0

sayhicoelho commented 2 years ago

I found this line that is closing the application after issuing a process error:

https://github.com/websockets/ws/blob/8.7.0/lib/websocket.js#L993

aysuio commented 2 years ago

I found this line that is closing the application after issuing a process error:

https://github.com/websockets/ws/blob/master/lib/websocket.js#L993

Hey, did you find any solution, met the exactly same problem... Still don't understand why this happens

sayhicoelho commented 2 years ago

@aysuio I stopped using this library and started using https://github.com/websockets/ws with my own implementation of reconnection.

websocketService.js

const WebSocket = require('ws')

function connect() {
  console.log('Connecting...')
  let ws = new WebSocket('ws://localhost:3333')

  ws.on('open', () => {
    console.log('Connection open')
  })

  ws.on('message', data => {
    console.log(data.toString('utf-8'))
  })

  ws.on('close', () => {
    console.log('Connection close')
    ws = null
    setTimeout(connect, 1000)
  })

  ws.on('error', err => {
    console.log('Connection error')
    console.error(err)
  })
}

connect()

ws version: ^8.8.1

To see it working, try to stop your ws server or add handshakeTimeout: 1 option to the 2nd parameter of WebSocket instance.

...
let ws = new WebSocket('ws://localhost:3333', { handshakeTimeout: 1 })
...

It should now reconnect after the timeout and when the network is down.

aysuio commented 2 years ago

@aysuio I stopped using this library and started using https://github.com/websockets/ws with my own implementation of reconnection.

websocketService.js

const WebSocket = require('ws')

function connect() {
  console.log('Connecting...')
  let ws = new WebSocket('ws://localhost:3333')

  ws.on('open', () => {
    console.log('Connection open')
  })

  ws.on('message', data => {
    console.log(data.toString('utf-8'))
  })

  ws.on('close', () => {
    console.log('Connection close')
    ws = null
    setTimeout(connect, 1000)
  })

  ws.on('error', err => {
    console.log('Connection error')
    console.error(err)
  })
}

connect()

ws version: ^8.8.1

To see it working, try to stop your ws server or add handshakeTimeout: 1 option to the 2nd parameter of WebSocket instance.

...
let ws = new WebSocket('ws://localhost:3333', { handshakeTimeout: 1 })
...

It should now reconnect after the timeout and when the network is down.

I also used that library instead of this one, which just costed me around 1 hour to implement the reconnection feature. Should have done this long time ago, XD.

Thanks for the reply