beyondcode / laravel-websockets

Websockets for Laravel. Done right.
https://beyondco.de/docs/laravel-websockets
MIT License
5.07k stars 612 forks source link

pusher-js did not reconnect after the 2nd offline situation ... #163

Closed ibrainventures closed 4 years ago

ibrainventures commented 5 years ago

First i will thank you very much for this Product. Wow!

We have a major Problem with our "little" websocket setup. Each time, (or better to say, after the 2nd Energy-Saver time of my Mobile Phone , my vue.js web-app failed to receive websocket events.

Our old Setup .. with the node.js based laravel-websocket-service / socket-io transport inside the frontend client was working over a year without this effect. So i started to investigate:

TLdr .. the pusher-js (version 4.4.x) is only reconnection 1 times on your laravel-websocket server after a (short) offline situation. This is also testable with firefox-dev there is a "offline-switch" ..

After the first "breakdown" it reconnects very fine ... your server is opening a new connection .. and voila ..

After the next offline-breakdown , the pusher-js is not re-connecting by websocket (ws or wss) it is preffering a xhr-streaming connection .. (this can be forbidden by:

disabledTransports: ['sockjs', 'xhr_polling', 'xhr_streaming'],

but .. if those transports are disabled .. it stops with re-connecting ..

I tested many variants of pusher-js connection params .. lastly ending with this list of "rules" ..

encrypted: true, wsHost: process.env.ECHO_SERVER_PUSHER, wssHost: process.env.ECHO_SERVER_PUSHER, httpHost: process.env.ECHO_SERVER_PUSHER, forceTLS: true, httpPort: 443, httpsPort: 443, wsPort: 443, wssPort: 443, // enabledTransports: ['ws', 'wss'], disabledTransports: ['sockjs', 'xhr_polling', 'xhr_streaming'], disableStats: true

but .. the pusher-js has his own rules (maybe .. because .. your product .. is tooo good ;-) ) ..

So .. if you want to be "pusher-js" free (it makes also sense, because you are digging with your product against their product) .. maybe you should take a look onto socket-io .. or ..

Or implement a xhr-streaming fallback possibility ..

With pusher-js directly on pusher.com it works without any problems, because they have the fallback transport mechanism .. so there is no breakdown ..

But with this limitation, its a showstopper ..

ibrainventures commented 5 years ago

Addendum:

The offline Situation to get this issue is a 2 seconds "offline" time ..

rahulhaque commented 5 years ago

Instead of using CDN, download and use the pusher.js locally. Search for sockjs_host, sockjs_http_port in pusher.js and change them to laravel websocket default 127.0.0.1 and 6001.

enzonotario commented 5 years ago

Hi! I also think that I have this problem with my ionic app.. when it is in background, and I open the app, the connection is lost and it doens't reconnect (I have to close completely the app to just boot again).. So, sorry but I don't understand you at all (I don't speak english).. what do you think would be the solution? Thanks in advance!

ibrainventures commented 5 years ago

@rahulhaque

Instead of using CDN, download and use the pusher.js locally. Search for sockjs_host, sockjs_http_port in pusher.js and change them to laravel websocket default 127.0.0.1 and 6001.

Thank you for the feedback! Did you solve a (on the 3rd attempt) re-connection problem with the this laravel-websockets server?

I tested your params and the connector is trying to connect on a:

http://192.168.0.1:6001/pusher/info

with a xhr / sockjs protocoll. But .. as i read it right, this server ist actually not supporting xhr requests. So this will only change the protocoll failure, but not with a working / successfull push mechanism.

ibrainventures commented 5 years ago

@enzonotario

Hi! I also think that I have this problem with my ionic app.. when it is in background, and I open the app, the connection is lost and it doens't reconnect (I have to close completely the app to just boot again).. So, sorry but I don't understand you at all (I don't speak english).. what do you think would be the solution? Thanks in advance!

There can be many reasons why a reconnection problem after (longer) standby occurs (eg. token-timeouts ...). But it sounds like "mine" problem. For Quickcheck, start your app, connect your websocket .. and after this try 2 times to go in flightmode (without wlan / 3g ..) (simulate a offline situation with 5 seconds) If after the 2nd (or 3rd) flightmode your app is still working with websockets you have a other problem :-)

enzonotario commented 5 years ago

@ibrainventures thanks so much! I tried what you said, and it only reconnects after the first time it goes to flightmode.. after the second time, it just doesn't reconnect and I have reboot the app... It seems that we have the same issue...

ibrainventures commented 5 years ago

@enzonotario as i wrote i my "opening entry" ... this is a major problem if you / we using pusher-js out of the box for this (acutally) server build without working xhr fallback on the server-side.

But .. acutally .. its no issue from the firm pusher.com , because their pusher-js is working with the pusher.com plattform without any problem (so you can doublecheck it, with using the pusher.com free account for testing .. and i am sure, that you can do x-thousand offline-simulations and it will reconnect ..)

And its no "real" issue from beyondcode / spatie , because their product laravel-websocket server is working ... (as a websocket-only-server). .. The answer can only give us the developers by himself ... the know by best their own roadmap ...

I am also relativly sure, that the underlying ratchet server is also supporting the xhr protocol, but without the dispatcher endpoints it will not work ...

enzonotario commented 5 years ago

ok, so maybe a solution would be to just catch the disconnection event and force a reconnection every X seconds... I have tried listenning to the states (https://pusher.com/docs/channels/using_channels/connection#available-states).. the first time it triggers a unavailable.. the second time a failed.. I tried to reconnect manually using echo.connector.pusher.connect(), it works, but those binded events are not triggered after this point.. so the next time that the app is disconnected, I just don't get the disconnected callback (to try to reconnect again and again)...

ibrainventures commented 5 years ago

@enzonotario
i also made some testings with the states interfaces and stuck inside the "pusher-own-rules" .. (if they cannot reconnect on xhr after the second downtime, they are blocking .. )

be sure, that you dissallow xhr and only make ws / wss connects .. sometimes the pusher-js is connecting with his own sockjs / pusher.com network and then your are "connected" but in the wrong network :-)

enabledTransports: ['ws', 'wss'], disabledTransports: ['sockjs', 'xhr_polling', 'xhr_streaming'],

.. ony really, really dirty hack - which works fine .. (but it is dirty) ... was following workflow:

-> App Start -> ws connect on channel "home" (id1) ---> all is working fine !!-> FIRST time the downtime / flightmode -> ws re-connect on channel "home" (id1) (automaticly by pusher-js) -> NOW (dirty) open a second ws connect (a new pusher/echo instance!) on channel "home" (id2) (i call it shadow) !!-> SECOND time the downtime / flightmode -> ws connect (id1) is not re-connecting (the issue effect) BUT ;-) --> ws connect (id2) is re-connecting on channel "home" ... (automaticly by pusher-js) -> again (dirty) open a second ws connect (a new pusher/echo instance!) on channel "home" (id3) LOOP :-)

Dirty:

but it works, but this "solution / workaround" is to buggy for a production way, and to fall back on xhr is no bad solution, because some clients / providers / firewalls / system-setups are not supporting ws connections.

so i am thinking about stepping back to socket.io / the laravel node.js websocket solution

platformsfx commented 5 years ago

A simple hack is to remove the pusher localStorage record: localStorage.removeItem('pusherTransportTLS'); This hack works fine for me.

ibrainventures commented 5 years ago

@platformsfx nice hack --- it doesn´t work / make any changes with my setup (vue js , spa application. Win Client, pusher 4.4.0 edition) Removed the cookie on all states, changes, app starts etc. ... (mine - actually on a non ssl setup is called pusherTransportNonTLS) .. also disabled cookies complete .. nope ..

@enzonotario i made a trace with the state_changes of the pusher-js 4.4.0 the pusher-js stops the the re-connection tries with the 2nd going offline i think, this is the same behaviour as you yesterday told ...

APP Start:

Here we go .. we are connected ..

{ "previous": "connecting", "current": "connected" }

1st Fligthmode Start ... { "previous": "connected", "current": "connecting" }

Still in Flightmode ..

{ "previous": "connecting", "current": "unavailable" } { "previous": "unavailable", "current": "connecting" }

1st - Flightmode Ended !: { "previous": "unavailable", "current": "connecting" }

{ "previous": "connecting", "current": "connected" }

we are back ...

2nd Fligthmode Start: (going offline)

{ "previous": "connected", "current": "failed" }

---> he is not waiting for a reconnection ... (maybe he is sulky ... ;-) )

enzonotario commented 5 years ago

I also tried what @platformsfx said, and I also have a pusherTransportNonTLS (that is weird because I think I have everything secured). I'm able to reconnect, even after multiple downsides.. the problem for me is that every connection doesn't send events to previously stablished connections to a determinate channel. I mean, when I subscribe to a channel, pusher sends new events to that subscribed observable. When I reconnect (via echo.connector.connect() or echo.connector.pusher.connect()) it seems to create a new connection, and every channel previously connected just aren't connected to this new connectoin... I hope you understand me :)

Even those binded events (i.e. connecting, connected, unavailable, failed) doesn't works anymore after the 2nd reconnection.

ibrainventures commented 5 years ago

@enzonotario I hope you understand me :)

not really :-) ..

Step by Step ? !

when your frontend app is re-connecting via the echo.channel "binding" .. what happens on your serverside ?

ibrainventures commented 5 years ago

btw: .. if you develop / debug this issue with chrome .. the developer tools "offline" switch did not work for the websocket connect ..

https://medium.com/@ngzhian/chrome-offline-network-emulation-and-websocket-6ecc914e2308

However, offline emulation does not work for WebSocket! I found a chromium bug that tracked this issue:

the offline switch inside firefox-developer edition / and also normal edition seems to be doing a complete "shutdown" ..


to de-attach this issue from all kind of server setups and front-end-surrounding (os, browser ..):

i tested the website:

https://laravel-websockets-example.alexbouma.me/

with a iphone / ios 12.1.4 (the good one .. )

2 x times "standby the phone" with the open safari browser on that side, the 3rd time the update is no more working ...

platformsfx commented 5 years ago

BTW, I'm using pusher-js Version 4.3.1. maybe it's the version issue ?

ibrainventures commented 5 years ago

@platformsfx

i staged pusher-js back to 4.3.1 and 4.2.2 and also staged laravel-echo back with some releases ..

In many of those combinations there are always other issues with reconnecting (btw. the pusher team often changes their internal debugging "slangs" :-) ) .. but no really (good) working pusher-js reconnection possible .. (always stopps with the second offline-event). I also tried your localforge-hack ...

at this point, i see for my problem no solution without the help of the @spatie @beyondcode team about the xhr possibility / enhancement .. that this also happens on long-time running websites (alexbouma.me) and on issue 165 there is a very near issue .. that makes me some more headache ..

ibrainventures commented 5 years ago

addendum

and only for the records ..

the official https://docs.beyondco.de/laravel-websockets/

also runs into a

https://sockjs.pusher.com/pusher/app/documentation/290/efsegdvk/xhr_streaming?protocol=7&client=js&version=4.3.1&t=1556713883303&n=5

connection, after the second downtime and stopps working with the bing-bing-bell-event ..

tahsin352 commented 5 years ago

same here.

after disabled transport for sockjs, xhr_pooling, xhr_streaming, now I am getting connecting -> failed.

ibrainventures commented 5 years ago

@tahsin352

i am a little disappointed, that there is no more progress inside this nice laravel extension .. Yes .. i know it is freeware, it is open to submit our own pr´s .. etc, ... but it was labeld as "websocket .. done right" and also a little side-hook against a splitted node.js solution ..

the irony is , that i am using this node.js solution now many month .. https://github.com/tlaverdure/laravel-echo-server and have no issue with re-connections ..

tahsin352 commented 5 years ago

@ibrainventures Thanks for suggestion. yah, node.js & socket.io are good alternative. i used firebase for realtime communication and state update successfully here. If anyone need help on it, plz let me know.

slothentic commented 3 years ago

For anyone else who is running into this problem, the actual issue is that the pusher-js library has a hard-coded setting buried in the codebase to revert to alternative (non websocket) connections after the second failed connection. This makes pusher-js unreliable for use with this package as the backend.

As a workaround, I've created a fork of the official pusher-js repo here: https://github.com/findmate/pusher-js-websocket-only

The only difference on this repo is it will always use websockets, and not revert to xhr streaming after the 2nd failed attempt. I will try to maintain this repo up to date with major/stable releases from Pusher going forward.

tibinvpaul commented 3 years ago

Hey @slothstronaut - thank you for the fork. Our users, especially from PWA were having connection issues and I am gonna try your fork!

rednazkela commented 2 years ago

For anyone stuck on this: I used the @slothstronaut fork to get the 99999 lives but it didn't fix the problem. I was curious about @rahulhaque comment and ended up changing all sockjs.pusher.com occurrences to "mydomain.com" and realized that sockjs was answering with a error code that breaks the reconnection cycle, but using mydomain.com is giving no answer so it keeps trying with all transport options until it reach wss again and reconnects

Thank you all

vladzorgan commented 2 years ago

Clear pusherTransportNonTLS key in localStorage can restart pusher after restarting websocket:server

SVV-team commented 2 years ago

Hi all found great solution ;)

  1. Bind to pusher event state_changed
  2. When state = disconnected call connect method ;)
  3. Enjoy !
window.Echo.connector.pusher.connection.bind('state_change', function(states) {
  if(states.current === 'disconnected') {
      window.Echo.connector.pusher.connect();
  }
});
nicholaszuccarelli commented 2 years ago

Hi all found great solution ;)

  1. Bind to pusher event state_changed
  2. When state = disconnected call connect method ;)
  3. Enjoy !
window.Echo.connector.pusher.connection.bind('state_change', function(states) {
  if(states.current === 'disconnected') {
      window.Echo.connector.pusher.connect();
  }
});

This didn't work for me unfortunately :( It returns unavailable when I try calling .connect()

Instead the only way I've been able to make it work if states.current === 'unavailable' then window.location.reload()

nholliday commented 2 years ago
window.Echo = new Echo({
    broadcaster: 'pusher',
    key: 'XXXXXXXXXX',
    wsHost: 'XXXXXXXXXX',
    disableStats: true
});
window.Echo.connector.pusher.connection.strategy.transports.wss.transport.manager.livesLeft = Infinity;

Seems to be working for me

kpebron commented 1 year ago
window.Echo = new Echo({
    broadcaster: 'pusher',
    key: 'XXXXXXXXXX',
    wsHost: 'XXXXXXXXXX',
    disableStats: true
});
window.Echo.connector.pusher.connection.strategy.transports.wss.transport.manager.livesLeft = Infinity;

Seems to be working for me

Thank you. This worked ! if you console.log(Echo.connector.pusher.connection.strategy.transports.wss.transport.manager), livesleft will return 2;