mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Construct storage data in the executor to avoid blocking the event loop (#113465)
Construct storage data in the executor Constructing storage data can be expensive for large files and can block the event loop. While ideally we optimize the construction of the data, there are some places we cannot make it any faster. To avoid blocking the loop, the construction of the data is now done in the executor by running the data_func in the executor. 2024-03-14 11:28:20.178 WARNING (MainThread) [asyncio] Executing <TimerHandle cancelled when=2319925.760294916 Store._async_schedule_callback_delayed_write() created at /Users/bdraco/home-assistant/homeassistant/helpers/storage.py:328> took 0.159 seconds There is some risk that the data_func is not thread-safe and needs to be run in the event loop, but I could not find any cases in our existing code where it would be a problem
This commit is contained in:
parent
f95d649f44
commit
28836be3eb
@ -374,10 +374,6 @@ class Store(Generic[_T]):
|
||||
return
|
||||
|
||||
data = self._data
|
||||
|
||||
if "data_func" in data:
|
||||
data["data"] = data.pop("data_func")()
|
||||
|
||||
self._data = None
|
||||
|
||||
if self._read_only:
|
||||
@ -395,6 +391,9 @@ class Store(Generic[_T]):
|
||||
"""Write the data."""
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
|
||||
if "data_func" in data:
|
||||
data["data"] = data.pop("data_func")()
|
||||
|
||||
_LOGGER.debug("Writing data for %s to %s", self.key, path)
|
||||
json_helper.save_json(
|
||||
path,
|
||||
|
@ -1356,6 +1356,10 @@ def mock_storage(
|
||||
# To ensure that the data can be serialized
|
||||
_LOGGER.debug("Writing data to %s: %s", store.key, data_to_write)
|
||||
raise_contains_mocks(data_to_write)
|
||||
|
||||
if "data_func" in data_to_write:
|
||||
data_to_write["data"] = data_to_write.pop("data_func")()
|
||||
|
||||
encoder = store._encoder
|
||||
if encoder and encoder is not JSONEncoder:
|
||||
# If they pass a custom encoder that is not the
|
||||
@ -1363,7 +1367,7 @@ def mock_storage(
|
||||
dump = ft.partial(json.dumps, cls=store._encoder)
|
||||
else:
|
||||
dump = _orjson_default_encoder
|
||||
data[store.key] = json.loads(dump(data_to_write))
|
||||
data[store.key] = json_loads(dump(data_to_write))
|
||||
|
||||
async def mock_remove(store: storage.Store) -> None:
|
||||
"""Remove data."""
|
||||
|
Loading…
x
Reference in New Issue
Block a user