diff --git a/homeassistant/helpers/storage.py b/homeassistant/helpers/storage.py index 9817f30f736..44460ffa601 100644 --- a/homeassistant/helpers/storage.py +++ b/homeassistant/helpers/storage.py @@ -133,12 +133,16 @@ class Store(Generic[_T]): Will ensure that when a call comes in while another one is in progress, the second call will wait and return the result of the first call. """ - if self._load_task is None: - self._load_task = self.hass.async_create_task( - self._async_load(), f"Storage load {self.key}" - ) + if self._load_task: + return await self._load_task - return await self._load_task + load_task = self.hass.async_create_task( + self._async_load(), f"Storage load {self.key}", eager_start=True + ) + if not load_task.done(): + # Only set the load task if it didn't complete immediately + self._load_task = load_task + return await load_task async def _async_load(self) -> _T | None: """Load the data and ensure the task is removed.""" @@ -318,7 +322,9 @@ class Store(Generic[_T]): # wrote. Reschedule the timer to the next write time. self._async_reschedule_delayed_write(self._next_write_time) return - self.hass.async_create_task(self._async_callback_delayed_write()) + self.hass.async_create_task( + self._async_callback_delayed_write(), eager_start=True + ) @callback def _async_ensure_final_write_listener(self) -> None: diff --git a/tests/helpers/test_storage.py b/tests/helpers/test_storage.py index 5382e18b15e..363f6051b96 100644 --- a/tests/helpers/test_storage.py +++ b/tests/helpers/test_storage.py @@ -115,7 +115,7 @@ async def test_loading_parallel( results = await asyncio.gather(store.async_load(), store.async_load()) assert results[0] == MOCK_DATA - assert results[0] is results[1] + assert results[1] == MOCK_DATA assert caplog.text.count(f"Loading data for {store.key}") @@ -795,6 +795,25 @@ async def test_os_error_is_fatal(tmpdir: py.path.local) -> None: ): await store.async_load() + # Verify second load is also failing + with pytest.raises(OSError), patch( + "homeassistant.helpers.storage.json_util.load_json", side_effect=OSError + ): + await store.async_load() + + await hass.async_stop(force=True) + + +async def test_json_load_failure(tmpdir: py.path.local) -> None: + """Test json load raising HomeAssistantError.""" + async with async_test_home_assistant() as hass: + tmp_storage = await hass.async_add_executor_job(tmpdir.mkdir, "temp_storage") + hass.config.config_dir = tmp_storage + + store = storage.Store( + hass, MOCK_VERSION_2, MOCK_KEY, minor_version=MOCK_MINOR_VERSION_1 + ) + await store.async_save({"hello": "world"}) base_os_error = OSError() base_os_error.errno = 30 home_assistant_error = HomeAssistantError()