Liveview does not reconnect when waking phone from sleep

Hello all!

We have noticed some interesting behavior when using our website on a mobile device.

Once someone has let their phone’s screen fall asleep and have had their phone idling for some time (in my testing somewhere around 10 minutes), when they open the browser again to our webpage, the livesocket does not reconnect.

This means that when the user clicks buttons on our forms that emit events for our live view to consume we receive nothing on our backend and there is no interactivity on the page.

The user must (currently) refresh the page for the socket to reconnect and for interactivity to resume.

Is there some sort of best practice for re-establishing this connection? Are we missing some configuration for resuming our connection? Why does the socket not reconnect in this case?

Thank you! :slight_smile:

4 Likes

What browser/platform? What Phoenix and LiveView version?

1 Like

Ah, sorry for the lack of details!

This seems to be occurring (so far accounted) on Safari (iOS) and Brave (Android).

We are using Phoenix 1.6.4 and LiveView version 0.17.5.

1 Like

Can you reliably recreate it? Are you using something like topbar? Is it showing when the page wakes up? Safari supports a remote web inspector if you’re able to recreate it and you can poke at the liveSocket to see what it says, such as liveSocket.isConnected() to verify that you aren’t in fact actually connected, but something else broke like a javascript error. More info would be helpful. I just tried to let mobile Safari (iOS15) sleep a LV tab half a dozen times and was not able to see any reconnection issues, so more info would be helpful.

4 Likes

@swiggins Did you ever find out the root cause of this?

I’m experiencing the same issue with mobile Firefox (Android). When the phone wakes up, the topbar loader is shown but it just loads forever and the page is no longer interactive.

I’ll do some more debugging as @chrismccord suggests, but if you’ve already solved the issue that would save me some effort. :grin:

I too have experienced this quite a bit. Happens both on mobile safari and chrome on desktop. Usually happens when my computer has been sleeping for a while with our liveview based web app open in the browser. Sometime it takes a minute or two to reconnect, sometimes it doesn’t and gets stuck with the top bar loading. Noticed this on other liveview sites like the dashboard on fly.io. I’ll try to get more info as well on the inspector.

I actually see this all the time on desktop FireFox. Every time I open the lid it doesn’t auto-reconnect. I hadn’t bothered to look into it yet as it was just a hobby project but interesting to know it’s happening to others.

I sometimes find the wait for re-connection to be a bit long (especially during dev, or on mobile when reopening the browser), and was reminded of the famous thing about elevator “close door” buttons that even though they often aren’t connected and don’t make the door close any quicker still give us a feeling of control (and something to do while we wait). Hence this implementation of a “Reconnect” button:

in app.js:

let execJS = (selector, attr) => {
  document.querySelectorAll(selector).forEach(el => liveSocket.execJS(el, el.getAttribute(attr)))
}

liveSocket.getSocket().onOpen(() => execJS("#connection-status", "js-hide"))
liveSocket.getSocket().onError(() => execJS("#connection-status", "js-show"))

and in your template near the flash messages:

    <div
      id="connection-status"
      class="hidden rounded-md bg-red-50 p-4 fixed top-1 right-1 fade-in-scale z-50"
      js-show={JS.show(js,
      time: 300,
      display: "inline-block",
      transition:
        {"ease-out duration-300", "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95",
         "opacity-100 translate-y-0 sm:scale-100"}
      )}
      js-hide={JS.hide(
      time: 300,
      transition:
        {"transition ease-in duration-300", "transform opacity-100 scale-100",
         "transform opacity-0 scale-95"}
      )}
    >
      <p class="text-sm font-medium text-red-800" role="alert">
        {l("Offline..")}
        <a class="btn btn-success btn-sm" href="javascript:liveSocket.connect()">Reconnect</a>
      </p>
    </div>
3 Likes

For others having this issue, I was able to fix this for my particular app. I increased the websocket :timeout on Phoenix.LiveView.Socket in my app’s Endpoint, like this:

socket "/live", Phoenix.LiveView.Socket,
    websocket: [timeout: 300_000, connect_info: [session: @session_options]]

The default is 60,000 milliseconds. You might have to tweak this number for your particular use case.

Hope that helps someone!

1 Like

Hi, I’m using the Websockets and channels for a PWA. We have a connected indicator, that shows, that the connection was not reestablished after the tablet woke up - funny fact: when I used the power button to lock the screen it worked - it was only after the display timeout, that this happend.

What I found out now was, that even if I use socket.connect() the connection was not reestablished. I head to socket.replaceTransport(socket.transport) or socket.disconnect(() => socket.connect()) to get it connected back.

After waking up the socket.conns WebSocket:

WebSocket{
    "timeout": 20000,
    "readyState": 3
}

Other stats:
Tablet: Samsung, Lenovo
Android: tested on: 7, 8, 9, 10
Chrome: all versions
Phoenix: 1.6.x, 1.7.x (actually 1.5.14 was the last version, that worked with this)

I hope this helps to dig deeper.

3 Likes