diff --git a/app/api/score_sub.py b/app/api/score_sub.py index b12d887..a5f0cb8 100644 --- a/app/api/score_sub.py +++ b/app/api/score_sub.py @@ -231,15 +231,21 @@ async def submit_score( if score_exists: return Response(b"error: no") - score.pp, score.sr = await app.usecases.performance.calculate_performance( - beatmap_id=beatmap.id, - beatmap_md5=beatmap.md5, - mode=score.mode, - mods=score.mods.value, - max_combo=score.max_combo, - accuracy=score.acc, - miss_count=score.nmiss, - ) + try: + score.pp, score.sr = await app.usecases.performance.calculate_performance( + beatmap_id=beatmap.id, + beatmap_md5=beatmap.md5, + mode=score.mode, + mods=score.mods.value, + max_combo=score.max_combo, + accuracy=score.acc, + miss_count=score.nmiss, + ) + except Exception: + logging.exception( + "Failed to calculate performance for score", + extra={"score_id": score.id}, + ) # calculate the score's status if score.passed: diff --git a/app/usecases/performance.py b/app/usecases/performance.py index cb00e6c..40b5275 100644 --- a/app/usecases/performance.py +++ b/app/usecases/performance.py @@ -1,13 +1,15 @@ from __future__ import annotations -import hashlib -import logging from typing import TypedDict +from tenacity import retry +from tenacity import stop_after_attempt +from tenacity import wait_exponential + import app.state import config from app.constants.mode import Mode -from app.objects.path import Path +from app.reliability import retry_if_exception_network_related class PerformanceScore(TypedDict): @@ -20,6 +22,12 @@ class PerformanceScore(TypedDict): miss_count: int +@retry( + retry=retry_if_exception_network_related(), + wait=wait_exponential(), + stop=stop_after_attempt(10), + reraise=True, +) async def calculate_performances( scores: list[PerformanceScore], ) -> list[tuple[float, float]]: @@ -27,18 +35,18 @@ async def calculate_performances( f"{config.PERFORMANCE_SERVICE_URL}/api/v1/calculate", json=scores, ) - if not response.is_success: - logging.error( - "Performance service returned non-2xx code on calculate_performances", - extra={"status": response.status_code}, - ) - return [(0.0, 0.0)] * len(scores) + response.raise_for_status() data = response.json() return [(result["pp"], result["stars"]) for result in data] -# TODO: split sr & pp calculations +@retry( + retry=retry_if_exception_network_related(), + wait=wait_exponential(), + stop=stop_after_attempt(10), + reraise=True, +) async def calculate_performance( *, beatmap_id: int, @@ -63,12 +71,7 @@ async def calculate_performance( }, ], ) - if response.status_code != 200: - logging.error( - "Performance service returned non-2xx code on calculate_performance", - extra={"status": response.status_code}, - ) - return 0.0, 0.0 + response.raise_for_status() data = response.json()[0] return data["pp"], data["stars"]