Skip to content

Commit

Permalink
Fix live logbook stalling when there are no historical events with a …
Browse files Browse the repository at this point in the history
…high commit interval (home-assistant#86110)

* Force live logbook to send an empty message to indicate no results

Since the sync task can take a while if the recorder is
busy, the logbook will appear to hang if we do not send
the first partial message even if its empty.

This work is in preparation for a higher database
commit interval where this issue is most obvious.

The historical only path did not have this issue because
it never had to wait for the db sync.

* update tests
  • Loading branch information
bdraco authored Jan 18, 2023
1 parent 87b2a73 commit 5279535
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 2 deletions.
10 changes: 8 additions & 2 deletions homeassistant/components/logbook/websocket_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ async def _async_send_historical_events(
formatter: Callable[[int, Any], dict[str, Any]],
event_processor: EventProcessor,
partial: bool,
force_send: bool = False,
) -> dt | None:
"""Select historical data from the database and deliver it to the websocket.
Expand Down Expand Up @@ -116,7 +117,7 @@ async def _async_send_historical_events(
# if its the last one (not partial) so
# consumers of the api know their request was
# answered but there were no results
if last_event_time or not partial:
if last_event_time or not partial or force_send:
connection.send_message(message)
return last_event_time

Expand Down Expand Up @@ -150,7 +151,7 @@ async def _async_send_historical_events(
# if its the last one (not partial) so
# consumers of the api know their request was
# answered but there were no results
if older_query_last_event_time or not partial:
if older_query_last_event_time or not partial or force_send:
connection.send_message(older_message)

# Returns the time of the newest event
Expand Down Expand Up @@ -384,6 +385,11 @@ def _queue_or_cancel(event: Event) -> None:
messages.event_message,
event_processor,
partial=True,
# Force a send since the wait for the sync task
# can take a a while if the recorder is busy and
# we want to make sure the client is not still spinning
# because it is waiting for the first message
force_send=True,
)

live_stream.task = asyncio.create_task(
Expand Down
18 changes: 18 additions & 0 deletions tests/components/logbook/test_websocket_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1817,6 +1817,7 @@ async def test_subscribe_unsubscribe_logbook_stream_device(
assert msg["id"] == 7
assert msg["type"] == TYPE_RESULT
assert msg["success"]
await async_wait_recording_done(hass)

# There are no answers to our initial query
# so we get an empty reply. This is to ensure
Expand All @@ -1828,6 +1829,15 @@ async def test_subscribe_unsubscribe_logbook_stream_device(
assert msg["id"] == 7
assert msg["type"] == "event"
assert msg["event"]["events"] == []
assert "partial" in msg["event"]
await async_wait_recording_done(hass)

msg = await asyncio.wait_for(websocket_client.receive_json(), 2)
assert msg["id"] == 7
assert msg["type"] == "event"
assert msg["event"]["events"] == []
assert "partial" not in msg["event"]
await async_wait_recording_done(hass)

hass.states.async_set("binary_sensor.should_not_appear", STATE_ON)
hass.states.async_set("binary_sensor.should_not_appear", STATE_OFF)
Expand Down Expand Up @@ -1942,6 +1952,14 @@ async def test_logbook_stream_match_multiple_entities(
assert msg["id"] == 7
assert msg["type"] == "event"
assert msg["event"]["events"] == []
assert "partial" in msg["event"]
await async_wait_recording_done(hass)

msg = await asyncio.wait_for(websocket_client.receive_json(), 2)
assert msg["id"] == 7
assert msg["type"] == "event"
assert msg["event"]["events"] == []
assert "partial" not in msg["event"]
await async_wait_recording_done(hass)

hass.states.async_set("binary_sensor.should_not_appear", STATE_ON)
Expand Down

0 comments on commit 5279535

Please sign in to comment.