From c8cc6fe00377dd2c57936c6e31043faa6bd4aa52 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 19 Feb 2025 20:11:37 +0100 Subject: [PATCH] Remove I/O in event loop for Home Assistant Core backup (#5648) * Remove I/O in event loop for Home Assistant Core backup The Home Assistant Core backup still contains some I/O in the event loop. Move all I/O into the executor. * Update supervisor/homeassistant/module.py Co-authored-by: Mike Degatano --------- Co-authored-by: Mike Degatano --- supervisor/homeassistant/module.py | 58 ++++++++++++++---------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/supervisor/homeassistant/module.py b/supervisor/homeassistant/module.py index 304ca8b46..395ed31b3 100644 --- a/supervisor/homeassistant/module.py +++ b/supervisor/homeassistant/module.py @@ -393,63 +393,59 @@ class HomeAssistant(FileConfiguration, CoreSysAttributes): async def backup( self, tar_file: tarfile.TarFile, exclude_database: bool = False ) -> None: - """Backup Home Assistant Core config/ directory.""" - await self.begin_backup() - try: + """Backup Home Assistant Core config/directory.""" + excludes = HOMEASSISTANT_BACKUP_EXCLUDE.copy() + if exclude_database: + excludes += HOMEASSISTANT_BACKUP_EXCLUDE_DATABASE + + def _is_excluded_by_filter(path: PurePath) -> bool: + """Filter function to filter out excluded files from the backup.""" + for exclude in excludes: + if not path.full_match(f"data/{exclude}"): + continue + _LOGGER.debug("Ignoring %s because of %s", path, exclude) + return True + + return False + + # Backup data config folder + def _write_tarfile(metadata: dict[str, Any]) -> None: + """Write tarfile.""" with TemporaryDirectory(dir=self.sys_config.path_tmp) as temp: temp_path = Path(temp) # Store local configs/state try: - write_json_file( - temp_path.joinpath("homeassistant.json"), self._data - ) + write_json_file(temp_path.joinpath("homeassistant.json"), metadata) except ConfigurationFileError as err: raise HomeAssistantError( f"Can't save meta for Home Assistant Core: {err!s}", _LOGGER.error, ) from err - # Backup data config folder - def _write_tarfile(): + try: with tar_file as backup: # Backup metadata backup.add(temp, arcname=".") - # Set excludes - excludes = HOMEASSISTANT_BACKUP_EXCLUDE.copy() - if exclude_database: - excludes += HOMEASSISTANT_BACKUP_EXCLUDE_DATABASE - - def is_excluded_by_filter(path: PurePath) -> bool: - """Filter to filter excludes.""" - for exclude in excludes: - if not path.full_match(f"data/{exclude}"): - continue - _LOGGER.debug( - "Ignoring %s because of %s", path, exclude - ) - return True - - return False - # Backup data atomic_contents_add( backup, self.sys_config.path_homeassistant, - file_filter=is_excluded_by_filter, + file_filter=_is_excluded_by_filter, arcname="data", ) - - try: - _LOGGER.info("Backing up Home Assistant Core config folder") - await self.sys_run_in_executor(_write_tarfile) - _LOGGER.info("Backup Home Assistant Core config folder done") except (tarfile.TarError, OSError) as err: raise HomeAssistantBackupError( f"Can't backup Home Assistant Core config folder: {str(err)}", _LOGGER.error, ) from err + + await self.begin_backup() + try: + _LOGGER.info("Backing up Home Assistant Core config folder") + await self.sys_run_in_executor(_write_tarfile, self._data) + _LOGGER.info("Backup Home Assistant Core config folder done") finally: await self.end_backup()