Thread Safe Downloads for Renderers (#49)

* Make engines download on another thread

* Fix merge issues
This commit is contained in:
2023-10-29 22:22:29 -05:00
committed by GitHub
parent dcc0504d3c
commit 6ce69c8d35

View File

@@ -13,6 +13,7 @@ logger = logging.getLogger()
class EngineManager: class EngineManager:
engines_path = None engines_path = None
download_tasks = []
@staticmethod @staticmethod
def supported_engines(): def supported_engines():
@@ -116,16 +117,34 @@ class EngineManager:
return None return None
@classmethod @classmethod
def download_engine(cls, engine, version, system_os=None, cpu=None): def is_already_downloading(cls, engine, version, system_os=None, cpu=None):
existing_download = cls.is_version_downloaded(engine, version, system_os, cpu) for task in cls.download_tasks:
if existing_download: task_parts = task.name.split('-')
logger.info(f"Requested download of {engine} {version}, but local copy already exists") task_engine, task_version, task_system_os, task_cpu = task_parts[:4]
return existing_download
if engine == task_engine and version == task_version:
if system_os in (task_system_os, None) and cpu in (task_cpu, None):
return task
return False
@classmethod
def download_engine(cls, engine, version, system_os=None, cpu=None, background=False):
def download_engine_task(engine, version, system_os=None, cpu=None):
existing_download = cls.is_version_downloaded(engine, version, system_os, cpu)
if existing_download:
logger.info(f"Requested download of {engine} {version}, but local copy already exists")
return existing_download
# Get the appropriate downloader class based on the engine type
cls.engine_with_name(engine).downloader().download_engine(version, download_location=cls.engines_path,
system_os=system_os, cpu=cpu, timeout=300)
# Check if the provided engine type is valid
engine_to_download = cls.engine_with_name(engine) engine_to_download = cls.engine_with_name(engine)
if not engine_to_download: existing_task = cls.is_already_downloading(engine, version, system_os, cpu)
logger.error("No valid engine found") if existing_task:
logger.debug(f"Already downloading {engine} {version}")
if not background:
existing_task.join() # If download task exists, wait until its done downloading
return return
elif not engine_to_download.downloader(): elif not engine_to_download.downloader():
logger.warning("No valid downloader for this engine. Please update this software manually.") logger.warning("No valid downloader for this engine. Please update this software manually.")
@@ -133,15 +152,19 @@ class EngineManager:
elif not cls.engines_path: elif not cls.engines_path:
raise FileNotFoundError("Engines path must be set before requesting downloads") raise FileNotFoundError("Engines path must be set before requesting downloads")
# Get the appropriate downloader class based on the engine type thread = threading.Thread(target=download_engine_task, args=(engine, version, system_os, cpu),
engine_to_download.downloader().download_engine(version, download_location=cls.engines_path, name=f'{engine}-{version}-{system_os}-{cpu}')
system_os=system_os, cpu=cpu, timeout=300) cls.download_tasks.append(thread)
thread.start()
# Check that engine was properly downloaded if background:
found_engine = cls.is_version_downloaded(engine, version, system_os, cpu) return thread
if not found_engine: else:
logger.error(f"Error downloading {engine}") thread.join()
return found_engine found_engine = cls.is_version_downloaded(engine, version, system_os, cpu) # Check that engine downloaded
if not found_engine:
logger.error(f"Error downloading {engine}")
return found_engine
@classmethod @classmethod
@@ -163,9 +186,9 @@ class EngineManager:
latest_version = engine.downloader().find_most_recent_version() latest_version = engine.downloader().find_most_recent_version()
if latest_version: if latest_version:
logger.debug(f"Latest version of {engine.name()} available: {latest_version.get('version')}") logger.debug(f"Latest version of {engine.name()} available: {latest_version.get('version')}")
if not cls.is_version_downloaded(engine, latest_version.get('version')): if not cls.is_version_downloaded(engine.name(), latest_version.get('version')):
logger.info(f"Downloading {engine.name()} ({latest_version['version']})") logger.info(f"Downloading latest version of {engine.name()}...")
cls.download_engine(engine=engine.name(), version=latest_version['version']) cls.download_engine(engine=engine.name(), version=latest_version['version'], background=True)
else: else:
logger.warning(f"Unable to get check for updates for {engine.name()}") logger.warning(f"Unable to get check for updates for {engine.name()}")
@@ -177,8 +200,6 @@ class EngineManager:
threads.append(thread) threads.append(thread)
thread.start() thread.start()
for thread in threads: # wait to finish
thread.join()
@classmethod @classmethod
def create_worker(cls, renderer, input_path, output_path, engine_version=None, args=None, parent=None, name=None): def create_worker(cls, renderer, input_path, output_path, engine_version=None, args=None, parent=None, name=None):