mirror of
https://github.com/home-assistant/core.git
synced 2025-07-20 11:47:06 +00:00
Refactor live history and logbook to avoid unnecessary task creation for recorder sync (#143244)
This commit is contained in:
parent
f873219d25
commit
aef266b940
@ -52,7 +52,7 @@ class HistoryLiveStream:
|
|||||||
subscriptions: list[CALLBACK_TYPE]
|
subscriptions: list[CALLBACK_TYPE]
|
||||||
end_time_unsub: CALLBACK_TYPE | None = None
|
end_time_unsub: CALLBACK_TYPE | None = None
|
||||||
task: asyncio.Task | None = None
|
task: asyncio.Task | None = None
|
||||||
wait_sync_task: asyncio.Task | None = None
|
wait_sync_future: asyncio.Future[None] | None = None
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@ -491,8 +491,8 @@ async def ws_stream(
|
|||||||
subscriptions.clear()
|
subscriptions.clear()
|
||||||
if live_stream.task:
|
if live_stream.task:
|
||||||
live_stream.task.cancel()
|
live_stream.task.cancel()
|
||||||
if live_stream.wait_sync_task:
|
if live_stream.wait_sync_future:
|
||||||
live_stream.wait_sync_task.cancel()
|
live_stream.wait_sync_future.cancel()
|
||||||
if live_stream.end_time_unsub:
|
if live_stream.end_time_unsub:
|
||||||
live_stream.end_time_unsub()
|
live_stream.end_time_unsub()
|
||||||
live_stream.end_time_unsub = None
|
live_stream.end_time_unsub = None
|
||||||
@ -554,10 +554,12 @@ async def ws_stream(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
live_stream.wait_sync_task = create_eager_task(
|
if sync_future := get_instance(hass).async_get_commit_future():
|
||||||
get_instance(hass).async_block_till_done()
|
# Set the future so we can cancel it if the client
|
||||||
)
|
# unsubscribes before the commit is done so we don't
|
||||||
await live_stream.wait_sync_task
|
# query the database needlessly
|
||||||
|
live_stream.wait_sync_future = sync_future
|
||||||
|
await live_stream.wait_sync_future
|
||||||
|
|
||||||
#
|
#
|
||||||
# Fetch any states from the database that have
|
# Fetch any states from the database that have
|
||||||
|
@ -47,7 +47,7 @@ class LogbookLiveStream:
|
|||||||
subscriptions: list[CALLBACK_TYPE]
|
subscriptions: list[CALLBACK_TYPE]
|
||||||
end_time_unsub: CALLBACK_TYPE | None = None
|
end_time_unsub: CALLBACK_TYPE | None = None
|
||||||
task: asyncio.Task | None = None
|
task: asyncio.Task | None = None
|
||||||
wait_sync_task: asyncio.Task | None = None
|
wait_sync_future: asyncio.Future[None] | None = None
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@ -329,8 +329,8 @@ async def ws_event_stream(
|
|||||||
subscriptions.clear()
|
subscriptions.clear()
|
||||||
if live_stream.task:
|
if live_stream.task:
|
||||||
live_stream.task.cancel()
|
live_stream.task.cancel()
|
||||||
if live_stream.wait_sync_task:
|
if live_stream.wait_sync_future:
|
||||||
live_stream.wait_sync_task.cancel()
|
live_stream.wait_sync_future.cancel()
|
||||||
if live_stream.end_time_unsub:
|
if live_stream.end_time_unsub:
|
||||||
live_stream.end_time_unsub()
|
live_stream.end_time_unsub()
|
||||||
live_stream.end_time_unsub = None
|
live_stream.end_time_unsub = None
|
||||||
@ -399,10 +399,12 @@ async def ws_event_stream(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
live_stream.wait_sync_task = create_eager_task(
|
if sync_future := get_instance(hass).async_get_commit_future():
|
||||||
get_instance(hass).async_block_till_done()
|
# Set the future so we can cancel it if the client
|
||||||
)
|
# unsubscribes before the commit is done so we don't
|
||||||
await live_stream.wait_sync_task
|
# query the database needlessly
|
||||||
|
live_stream.wait_sync_future = sync_future
|
||||||
|
await live_stream.wait_sync_future
|
||||||
|
|
||||||
#
|
#
|
||||||
# Fetch any events from the database that have
|
# Fetch any events from the database that have
|
||||||
|
@ -1307,11 +1307,17 @@ class Recorder(threading.Thread):
|
|||||||
|
|
||||||
async def async_block_till_done(self) -> None:
|
async def async_block_till_done(self) -> None:
|
||||||
"""Async version of block_till_done."""
|
"""Async version of block_till_done."""
|
||||||
|
if future := self.async_get_commit_future():
|
||||||
|
await future
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_get_commit_future(self) -> asyncio.Future[None] | None:
|
||||||
|
"""Return a future that will wait for the next commit or None if nothing pending."""
|
||||||
if self._queue.empty() and not self._event_session_has_pending_writes:
|
if self._queue.empty() and not self._event_session_has_pending_writes:
|
||||||
return
|
return None
|
||||||
event = asyncio.Event()
|
future: asyncio.Future[None] = self.hass.loop.create_future()
|
||||||
self.queue_task(SynchronizeTask(event))
|
self.queue_task(SynchronizeTask(future))
|
||||||
await event.wait()
|
return future
|
||||||
|
|
||||||
def block_till_done(self) -> None:
|
def block_till_done(self) -> None:
|
||||||
"""Block till all events processed.
|
"""Block till all events processed.
|
||||||
|
@ -317,13 +317,18 @@ class SynchronizeTask(RecorderTask):
|
|||||||
"""Ensure all pending data has been committed."""
|
"""Ensure all pending data has been committed."""
|
||||||
|
|
||||||
# commit_before is the default
|
# commit_before is the default
|
||||||
event: asyncio.Event
|
future: asyncio.Future
|
||||||
|
|
||||||
def run(self, instance: Recorder) -> None:
|
def run(self, instance: Recorder) -> None:
|
||||||
"""Handle the task."""
|
"""Handle the task."""
|
||||||
# Does not use a tracked task to avoid
|
# Does not use a tracked task to avoid
|
||||||
# blocking shutdown if the recorder is broken
|
# blocking shutdown if the recorder is broken
|
||||||
instance.hass.loop.call_soon_threadsafe(self.event.set)
|
instance.hass.loop.call_soon_threadsafe(self._set_result_if_not_done)
|
||||||
|
|
||||||
|
def _set_result_if_not_done(self) -> None:
|
||||||
|
"""Set the result if not done."""
|
||||||
|
if not self.future.done():
|
||||||
|
self.future.set_result(None)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(slots=True)
|
@dataclass(slots=True)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user