From 27466984dfaad20fbcac690dfc47f012290df665 Mon Sep 17 00:00:00 2001 From: Eric Callahan Date: Mon, 28 Feb 2022 19:30:34 -0500 Subject: [PATCH] update_manager: fix blocking I/O When using tempfile.TemporaryDirectory it is possible that exiting the context will block when attempting to delete the temporary directory. Don't use the context manager, instead create and cleanup the temp dir using the default threadpoolexecutor. Signed-off-by: Eric Callahan --- .../components/update_manager/update_manager.py | 15 ++++++++++++--- moonraker/components/update_manager/zip_deploy.py | 9 +++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/moonraker/components/update_manager/update_manager.py b/moonraker/components/update_manager/update_manager.py index a9121fc..18eff99 100644 --- a/moonraker/components/update_manager/update_manager.py +++ b/moonraker/components/update_manager/update_manager.py @@ -602,6 +602,13 @@ class CommandHelper: self.notify_update_response( f"Downloading {self.cur_update_app}: {totals} [{progress}%]") + async def create_tempdir(self, suffix=None, prefix=None): + def _createdir(sfx, pfx): + return tempfile.TemporaryDirectory(suffix=sfx, prefix=pfx) + + eventloop = self.server.get_event_loop() + return await eventloop.run_in_thread(_createdir, suffix, prefix) + class PackageDeploy(BaseDeploy): def __init__(self, config: ConfigHelper, @@ -1218,9 +1225,9 @@ class WebClientDeploy(BaseDeploy): f"Updating Web Client {self.name}...") self.cmd_helper.notify_update_response( f"Downloading Client: {self.name}") - with tempfile.TemporaryDirectory( - suffix=self.name, prefix="client") as tempdirname: - tempdir = pathlib.Path(tempdirname) + td = await self.cmd_helper.create_tempdir(self.name, "client") + try: + tempdir = pathlib.Path(td.name) temp_download_file = tempdir.joinpath(f"{self.name}.zip") temp_persist_dir = tempdir.joinpath(self.name) client = self.cmd_helper.get_http_client() @@ -1232,6 +1239,8 @@ class WebClientDeploy(BaseDeploy): await event_loop.run_in_thread( self._extract_release, temp_persist_dir, temp_download_file) + finally: + await event_loop.run_in_thread(td.cleanup) self.version = self.remote_version version_path = self.path.joinpath(".version") if not version_path.exists(): diff --git a/moonraker/components/update_manager/zip_deploy.py b/moonraker/components/update_manager/zip_deploy.py index 227e2e4..393dd6e 100644 --- a/moonraker/components/update_manager/zip_deploy.py +++ b/moonraker/components/update_manager/zip_deploy.py @@ -11,7 +11,6 @@ import json import shutil import re import time -import tempfile import zipfile from .app_deploy import AppDeploy from utils import verify_source @@ -378,9 +377,9 @@ class ZipDeploy(AppDeploy): npm_hash = await self._get_file_hash(self.npm_pkg_json) dl_url, content_type, size = self.release_download_info self.notify_status("Starting Download...") - with tempfile.TemporaryDirectory( - suffix=self.name, prefix="app") as tempdirname: - tempdir = pathlib.Path(tempdirname) + td = await self.cmd_helper.create_tempdir(self.name, "app") + try: + tempdir = pathlib.Path(td.name) temp_download_file = tempdir.joinpath(f"{self.name}.zip") client = self.cmd_helper.get_http_client() await client.download_file( @@ -391,6 +390,8 @@ class ZipDeploy(AppDeploy): event_loop = self.server.get_event_loop() await event_loop.run_in_thread( self._extract_release, temp_download_file) + finally: + await event_loop.run_in_thread(td.cleanup) await self._update_dependencies(npm_hash, force=force_dep_update) await self._update_repo_state() await self.restart_service()