This commit is contained in:
2025-05-08 08:52:20 +00:00
parent 0a55a98a63
commit 495690f7cd

View File

@@ -200,6 +200,9 @@ ALLOWED_TARGET_BRANCHES = []
# GLOBALE HELPER FUNCTIONS (PART 1: Retry Decorator)
# ==============================================================================
# Imports für den Retry Decorator (um NameErrors zu vermeiden)
from openai.error import AuthenticationError, OpenAIError, RateLimitError, APIError, Timeout, InvalidRequestError, ServiceUnavailableError # Beispielhafte spezifische Fehler
# Logger fuer den Retry Decorator selbst (Nutzt den globalen Root Logger)
decorator_logger = logging.getLogger(__name__ + ".Retry")
@@ -229,7 +232,7 @@ def retry_on_failure(func):
# Fehler loggen und weitergeben, wenn keine Retries konfiguriert sind
decorator_logger.error(f"FEHLER bei '{effective_func_name}' (keine Retries konfiguriert). {type(e).__name__} - {str(e)[:150]}...")
# Log traceback fuer unerwartete Fehler (nicht die spezifischen API/Netzwerkfehler)
if not isinstance(e, (requests.exceptions.RequestException, gspread.exceptions.APIError, openai.error.OpenAIError, wikipedia.exceptions.WikipediaException)):
if not isinstance(e, (requests.exceptions.RequestException, gspread.exceptions.APIError, OpenAIError, wikipedia.exceptions.WikipediaException)): # <<< GEÄNDERT (openai.error.OpenAIError -> OpenAIError)
decorator_logger.exception("Details zum Fehler:")
raise e # Re-raise the exception
@@ -245,7 +248,7 @@ def retry_on_failure(func):
return func(*args, **kwargs) # Call the original function
# Spezifische Exceptions, die ein Retry nicht rechtfertigen (permanente Fehler)
except (gspread.exceptions.SpreadsheetNotFound, openai.error.AuthenticationError, ValueError) as e:
except (gspread.exceptions.SpreadsheetNotFound, AuthenticationError, ValueError) as e: # <<< GEÄNDERT (openai.error.AuthenticationError -> AuthenticationError)
# Diese Fehler deuten auf ein permanentes Problem hin (falsche URL, falscher Key, falsche Eingabe)
decorator_logger.critical(f"❌ ENDGUELTIGER FEHLER bei '{effective_func_name}': Permanentes Problem erkannt. {type(e).__name__} - {str(e)[:150]}...")
decorator_logger.exception("Details:") # Log traceback fuer permanente Fehler
@@ -269,20 +272,24 @@ def retry_on_failure(func):
# Fangen Sie andere wiederholbare Exceptions (Netzwerk, Rate Limit, Timeout etc.)
except (requests.exceptions.RequestException, gspread.exceptions.APIError, openai.error.OpenAIError, wikipedia.exceptions.WikipediaException) as e:
except (requests.exceptions.RequestException, gspread.exceptions.APIError, OpenAIError, wikipedia.exceptions.WikipediaException) as e: # <<< GEÄNDERT (openai.error.OpenAIError -> OpenAIError)
error_msg = str(e)
error_type = type(e).__name__
if attempt < max_retries_config - 1: # Wenn nicht der letzte Versuch
wait_time = base_delay * (2 ** attempt) + random.uniform(0, 1) # Exponentieller Backoff mit Jitter
# Loggen Sie den spezifischen Fehler und die Wartezeit
if isinstance(e, gspread.exceptions.APIError) and hasattr(e, 'response') and e.response is not None and e.response.status_code == 429:
if isinstance(e, RateLimitError): # <<< GEÄNDERT (Prüfung auf spezifischen OpenAI Fehler)
decorator_logger.warning(f"🚦 RATE LIMIT ({error_type}) bei '{effective_func_name}' (Versuch {attempt+1}/{max_retries_config}). {error_msg[:150]}... Warte {wait_time:.2f}s...")
elif isinstance(e, Timeout) and isinstance(e, OpenAIError): # <<< GEÄNDERT (Prüfung auf OpenAI Timeout)
decorator_logger.warning(f"⏰ OPENAI TIMEOUT ({error_type}) bei '{effective_func_name}' (Versuch {attempt+1}/{max_retries_config}). {error_msg[:150]}... Warte {wait_time:.2f}s...")
elif isinstance(e, gspread.exceptions.APIError) and hasattr(e, 'response') and e.response is not None and e.response.status_code == 429: # <<< GEÄNDERT (Gspread Rate Limit Check)
decorator_logger.warning(f"🚦 GSPREAD RATE LIMIT ({error_type}) bei '{effective_func_name}' (Versuch {attempt+1}/{max_retries_config}). {error_msg[:150]}... Warte {wait_time:.2f}s...")
elif isinstance(e, requests.exceptions.Timeout):
decorator_logger.warning(f"⏰ TIMEOUT ({error_type}) bei '{effective_func_name}' (Versuch {attempt+1}/{max_retries_config}). {error_msg[:150]}... Warte {wait_time:.2f}s...")
decorator_logger.warning(f" REQUESTS TIMEOUT ({error_type}) bei '{effective_func_name}' (Versuch {attempt+1}/{max_retries_config}). {error_msg[:150]}... Warte {wait_time:.2f}s...")
elif isinstance(e, requests.exceptions.RequestException): # Allgemeine RequestException
decorator_logger.warning(f"🌐 NETZWERKFEHLER ({error_type}) bei '{effective_func_name}' (Versuch {attempt+1}/{max_retries_config}). {error_msg[:150]}... Warte {wait_time:.2f}s...")
elif isinstance(e, openai.error.OpenAIError): # Allgemeine OpenAI Fehler
elif isinstance(e, OpenAIError): # Allgemeine OpenAI Fehler
decorator_logger.warning(f"🤖 OPENAI FEHLER ({error_type}) bei '{effective_func_name}' (Versuch {attempt+1}/{max_retries_config}). {error_msg[:150]}... Warte {wait_time:.2f}s...")
elif isinstance(e, wikipedia.exceptions.WikipediaException): # Allgemeine Wikipedia Fehler
decorator_logger.warning(f"📚 WIKIPEDIA FEHLER ({error_type}) bei '{effective_func_name}' (Versuch {attempt+1}/{max_retries_config}). {error_msg[:150]}... Warte {wait_time:.2f}s...")
@@ -305,10 +312,8 @@ def retry_on_failure(func):
# und eine Exception immer zu einer raise e Anweisung führt.
raise RuntimeError(f"Retry decorator logic error: Loop completed unexpectedly for {effective_func_name}. This should not happen.")
return wrapper # Gibt die Wrapper-Funktion zurück
# ==============================================================================
# Ende Retry Decorator Block
# ==============================================================================