🎨 Added delay before manager retry
This commit is contained in:
@@ -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"""
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user