🎨 Added delay before manager retry

This commit is contained in:
GeoffreyCoulaud
2023-06-05 00:17:41 +02:00
parent 1e4004329c
commit ff0ba00733
2 changed files with 35 additions and 25 deletions

View File

@@ -1,7 +1,8 @@
import logging import logging
from abc import abstractmethod from abc import abstractmethod
from typing import Any, Callable
from threading import Lock from threading import Lock
from time import sleep
from typing import Any, Callable
from src.game import Game from src.game import Game
@@ -17,7 +18,10 @@ class Manager:
run_after: set[type["Manager"]] = set() run_after: set[type["Manager"]] = set()
blocking: bool = True blocking: bool = True
retryable_on: set[type[Exception]] = set() retryable_on: set[type[Exception]] = set()
continue_on: set[type[Exception]] = set()
retry_delay: int = 3
max_tries: int = 3 max_tries: int = 3
errors: list[Exception] errors: list[Exception]
@@ -54,31 +58,35 @@ class Manager:
* May raise other exceptions that will be reported * May raise other exceptions that will be reported
""" """
def execute_resilient_manager_logic(self, game: Game) -> None: def execute_resilient_manager_logic(self, game: Game, try_index: int = 0) -> None:
"""Execute the manager logic and handle its errors by reporting them or retrying""" """Execute the manager logic and handle its errors by reporting them or retrying"""
for remaining_tries in range(self.max_tries, -1, -1): try:
try: self.manager_logic(game)
self.manager_logic(game) except Exception as error:
except Exception as error: if error in self.continue_on:
# Handle unretryable errors # Handle skippable errors (skip silently)
log_args = (type(error).__name__, self.name, game.name, game.game_id) return
if type(error) not in self.retryable_on: elif error in self.retryable_on:
logging.error( if try_index < self.max_tries:
"Unretryable %s in %s for %s (%s)", *log_args, exc_info=error # Handle retryable errors
) logging_format = "Retrying %s in %s for %s"
self.report_error(error) sleep(self.retry_delay)
break self.execute_resilient_manager_logic(game, try_index + 1)
# Handle being out of retries
elif remaining_tries == 0:
logging.error(
"Too many retries due to %s in %s for %s (%s)", *log_args
)
self.report_error(error)
break
# Retry
else: else:
logging.debug("Retry caused by %s in %s for %s (%s)", *log_args) # Handle being out of retries
continue logging_format = "Out of retries dues to %s in %s for %s"
self.report_error(error)
else:
# Handle unretryable errors
logging_format = "Unretryable %s in %s for %s"
self.report_error(error)
# Finally log errors
logging.error(
logging_format,
type(error).__name__,
self.name,
f"{game.name} ({game.game_id})",
)
def process_game(self, game: Game, callback: Callable[["Manager"], Any]) -> None: def process_game(self, game: Game, callback: Callable[["Manager"], Any]) -> None:
"""Pass the game through the manager""" """Pass the game through the manager"""

View File

@@ -1,3 +1,5 @@
from urllib3.exceptions import SSLError
from src.game import Game from src.game import Game
from src.store.managers.async_manager import AsyncManager from src.store.managers.async_manager import AsyncManager
from src.utils.steam import ( from src.utils.steam import (
@@ -11,7 +13,7 @@ from src.utils.steam import (
class SteamAPIManager(AsyncManager): class SteamAPIManager(AsyncManager):
"""Manager in charge of completing a game's data from the Steam API""" """Manager in charge of completing a game's data from the Steam API"""
retryable_on = set((HTTPError,)) retryable_on = set((HTTPError, SSLError))
def manager_logic(self, game: Game) -> None: def manager_logic(self, game: Game) -> None:
# Skip non-steam games # Skip non-steam games