From 989c54001c73bf56caa10780227e463faf7b1a45 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Mon, 8 Dec 2025 16:53:30 +0100 Subject: [PATCH] added retries in thumbnail integration --- .../plugins/publish/integrate_thumbnail.py | 82 +++++++++++++++++-- 1 file changed, 73 insertions(+), 9 deletions(-) diff --git a/client/ayon_core/plugins/publish/integrate_thumbnail.py b/client/ayon_core/plugins/publish/integrate_thumbnail.py index 067c3470e8..7d36a1c7eb 100644 --- a/client/ayon_core/plugins/publish/integrate_thumbnail.py +++ b/client/ayon_core/plugins/publish/integrate_thumbnail.py @@ -24,11 +24,19 @@ import os import collections +import time import pyblish.api import ayon_api from ayon_api import RequestTypes from ayon_api.operations import OperationsSession +try: + from ayon_api.utils import get_media_mime_type +except ImportError: + from ayon_core.lib import get_media_mime_type +import requests + +from ayon_core.pipeline.publish import PublishXmlValidationError InstanceFilterResult = collections.namedtuple( @@ -170,19 +178,16 @@ class IntegrateThumbnailsAYON(pyblish.api.ContextPlugin): fix jpeg mime type. """ - mime_type = None - with open(src_filepath, "rb") as stream: - if b"\xff\xd8\xff" == stream.read(3): - mime_type = "image/jpeg" - + mime_type = get_media_mime_type(src_filepath) if mime_type is None: - return ayon_api.create_thumbnail(project_name, src_filepath) + return ayon_api.create_thumbnail( + project_name, src_filepath + ) - response = ayon_api.upload_file( + response = self._upload_with_retries( f"projects/{project_name}/thumbnails", src_filepath, - request_type=RequestTypes.post, - headers={"Content-Type": mime_type}, + mime_type, ) response.raise_for_status() return response.json()["id"] @@ -248,3 +253,62 @@ class IntegrateThumbnailsAYON(pyblish.api.ContextPlugin): or instance.data.get("name") or "N/A" ) + + def _upload_with_retries( + self, + endpoint: str, + repre_path: str, + content_type: str, + ): + """Upload file with simple exponential backoff retries. + + If all retries fail we raise a PublishXmlValidationError with a help key + to guide the user to retry publish. + """ + # How long to sleep before next attempt + wait_time = 1 + filename = os.path.basename(repre_path) + + ayon_con = ayon_api.get_server_api_connection() + headers = ayon_con.get_headers(content_type) + max_retries = ayon_con.get_default_max_retries() + last_error = None + for attempt in range(max_retries): + attempt += 1 + try: + return ayon_con.upload_file( + endpoint, + repre_path, + headers=headers, + request_type=RequestTypes.post, + ) + + except ( + requests.exceptions.Timeout, + requests.exceptions.ConnectionError + ): + # Log and retry with backoff if attempts remain + if attempt >= max_retries: + raise + + self.log.warning( + f"Review upload failed ({attempt}/{max_retries})." + f" Retrying in {wait_time}s...", + exc_info=True, + ) + time.sleep(wait_time) + + # Exhausted retries - raise a user-friendly validation error with help + raise PublishXmlValidationError( + self, + ( + "Upload of thumbnail timed out or failed after multiple" + " attempts. Please try publishing again." + ), + formatting_data={ + "upload_type": "Thumbnail", + "file": repre_path, + "error": str(last_error), + }, + help_filename="upload_file.xml", + )