home-assistant / frontend

:lollipop: Frontend for Home Assistant
https://demo.home-assistant.io
Other
4.02k stars 2.75k forks source link

On tab visible, connectedCallback of panel triggers websocket messages before connection established #6236

Closed balloob closed 4 years ago

balloob commented 4 years ago

Checklist

The problem

When we are away from the tab for 5 minutes, we disconnect the panel from the DOM and disconnect the websocket connection.

When we navigate back to the tab, we will reconnect the panel to the DOM and re-open the connection.

Reconnecting the panel to the DOM will trigger connectedCallback, which in the case of <hui-image> can involve getting a signed path to be able to show a preview of a camera. This request fails with WebSocket is already in CLOSING or CLOSED state.

function file
sendMessage @ VM2676 connection.js:135
eval @ VM2676 connection.js:146
sendMessagePromise @ VM2676 connection.js:139
callWS @ connection-mixin.ts?cbf4:105
getSignedPath @ auth.ts?cd5f:25
fetchThumbnailUrl @ camera.ts?0862:40
timeCachePromiseFunc @ time-cache-function-promise.ts?9322:31
fetchThumbnailUrlWithCache @ camera.ts?0862:24
_updateCameraImageSrc @ hui-image.ts?b3d5:211
updated @ hui-image.ts?b3d5:166
performUpdate @ updating-element.ts?6e6a:774
_enqueueUpdate @ updating-element.ts?6e6a:713
async function (async)
_enqueueUpdate @ updating-element.ts?6e6a:708
_requestUpdate @ updating-element.ts?6e6a:678
initialize @ updating-element.ts?6e6a:520
initialize @ lit-element.ts?a751:137
UpdatingElement @ updating-element.ts?6e6a:509
LitElement @ lit-element.ts?a751:44
HuiImage @ hui-image.ts?b3d5:28
_clone @ template-instance.ts?03a5:97
__commitTemplateResult @ parts.ts?8848:279
commit @ parts.ts?8848:221
render @ render.ts?5dc5:55
render @ shady-render.ts?29b8:277
update @ lit-element.ts?a751:215
performUpdate @ updating-element.ts?6e6a:757
_enqueueUpdate @ updating-element.ts?6e6a:713
async function (async)
_enqueueUpdate @ updating-element.ts?6e6a:708
_requestUpdate @ updating-element.ts?6e6a:678
initialize @ updating-element.ts?6e6a:520
initialize @ lit-element.ts?a751:137
UpdatingElement @ updating-element.ts?6e6a:509
LitElement @ lit-element.ts?a751:44
HuiPictureEntityCard @ hui-picture-entity-card.ts?7cea:32
_createElement @ create-element-base.ts?79ca:73
_lazyCreate @ create-element-base.ts?79ca:116
tryCreateLovelaceElement @ create-element-base.ts?79ca:216
createLovelaceElement @ create-element-base.ts?79ca:150
createCardElement @ create-card-element.ts?f0ee:68
createCardElement @ hui-view.ts?56bc:73
eval @ hui-view.ts?56bc:315
_createCards @ hui-view.ts?56bc:314
updated @ hui-view.ts?56bc:158
performUpdate @ updating-element.ts?6e6a:774
_enqueueUpdate @ updating-element.ts?6e6a:713
async function (async)
_enqueueUpdate @ updating-element.ts?6e6a:708
_requestUpdate @ updating-element.ts?6e6a:678
initialize @ updating-element.ts?6e6a:520
initialize @ lit-element.ts?a751:137
UpdatingElement @ updating-element.ts?6e6a:509
LitElement @ lit-element.ts?a751:44
HUIView @ hui-view.ts?56bc:67
_selectView @ hui-root.ts?49a9:629
eval @ hui-root.ts?49a9:453
setTimeout (async)
eval @ render-status.ts?bfb9:2
eval @ timeline.js?905f:20
requestAnimationFrame (async)
window.requestAnimationFrame @ timeline.js?905f:19
afterNextRender @ render-status.ts?bfb9:2
updated @ hui-root.ts?49a9:453
performUpdate @ updating-element.ts?6e6a:774
_enqueueUpdate @ updating-element.ts?6e6a:713
async function (async)
_enqueueUpdate @ updating-element.ts?6e6a:708
_requestUpdate @ updating-element.ts?6e6a:678
initialize @ updating-element.ts?6e6a:520
initialize @ lit-element.ts?a751:137
UpdatingElement @ updating-element.ts?6e6a:509
LitElement @ lit-element.ts?a751:44
HUIRoot @ hui-root.ts?49a9:84
_clone @ template-instance.ts?03a5:97
__commitTemplateResult @ parts.ts?8848:279
commit @ parts.ts?8848:221
render @ render.ts?5dc5:55
render @ shady-render.ts?29b8:277
update @ lit-element.ts?a751:215
performUpdate @ updating-element.ts?6e6a:757
_enqueueUpdate @ updating-element.ts?6e6a:713
async function (async)
_enqueueUpdate @ updating-element.ts?6e6a:708
_requestUpdate @ updating-element.ts?6e6a:678
set @ updating-element.ts?6e6a:364
_setLovelaceConfig @ ha-panel-lovelace.ts?b841:326
_regenerateConfig @ ha-panel-lovelace.ts?b841:187
async function (async)
_regenerateConfig @ ha-panel-lovelace.ts?b841:186
connectedCallback @ ha-panel-lovelace.ts?b841:83
_handleVisibilityChange @ partial-panel-resolver.ts?d4cd:173
eval @ partial-panel-resolver.ts?d4cd:101

Expected behavior

Steps to reproduce

Load demo integration, leave tab hidden for 5 minutes, navigate back.

Environment

State of relevant entities

Problem-relevant configuration

Javascript errors shown in your browser console/inspector

Additional information

balloob commented 4 years ago

Also happens on non-default Lovelace dashboards in panel disconnect

image

balloob commented 4 years ago

In this case unsubscribing is actually not necessary, we will resub automatically on reconnect. But the panel doesn't know that, it just knows it's being disconnected and should not use resources.

I am going to make this logic opt-in, mark it experimental while we figure out the bugs.

balloob commented 4 years ago

image

Profile panel had one too.

One thing that we can explore is that if a connection is suspended, we want to hold onto all messages that are in flight? However, that is also dangerous as that can queue up a lot of requests !

balloob commented 4 years ago

Maybe if we know that we're soon going to reconnect the WS connection, we can enable "queueIfDisconnected" setting, and then disable that after we're connected again. We would put that in home-assistant.ts.

balloob commented 4 years ago

This should help:

https://github.com/home-assistant/home-assistant-js-websocket/pull/125

https://github.com/home-assistant/home-assistant-js-websocket/pull/126