feat(fetcher): replace HTTPError with NoBeatmapError for better error handling
This commit is contained in:
@@ -16,6 +16,12 @@ urls = [
|
|||||||
logger = fetcher_logger("BeatmapRawFetcher")
|
logger = fetcher_logger("BeatmapRawFetcher")
|
||||||
|
|
||||||
|
|
||||||
|
class NoBeatmapError(Exception):
|
||||||
|
"""Beatmap 不存在异常"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BeatmapRawFetcher(BaseFetcher):
|
class BeatmapRawFetcher(BaseFetcher):
|
||||||
def __init__(self, client_id: str = "", client_secret: str = "", **kwargs):
|
def __init__(self, client_id: str = "", client_secret: str = "", **kwargs):
|
||||||
# BeatmapRawFetcher 不需要 OAuth,传递空值给父类
|
# BeatmapRawFetcher 不需要 OAuth,传递空值给父类
|
||||||
@@ -107,12 +113,12 @@ class BeatmapRawFetcher(BaseFetcher):
|
|||||||
|
|
||||||
if resp.status_code >= 400:
|
if resp.status_code >= 400:
|
||||||
logger.warning(f"Beatmap {beatmap_id} from {req_url}: HTTP {resp.status_code}")
|
logger.warning(f"Beatmap {beatmap_id} from {req_url}: HTTP {resp.status_code}")
|
||||||
last_error = HTTPError(f"HTTP {resp.status_code}")
|
last_error = NoBeatmapError(f"HTTP {resp.status_code}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not resp.text:
|
if not resp.text:
|
||||||
logger.warning(f"Beatmap {beatmap_id} from {req_url}: empty response")
|
logger.warning(f"Beatmap {beatmap_id} from {req_url}: empty response")
|
||||||
last_error = HTTPError("Empty response")
|
last_error = NoBeatmapError("Empty response")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logger.debug(f"Successfully fetched beatmap {beatmap_id} from {req_url}")
|
logger.debug(f"Successfully fetched beatmap {beatmap_id} from {req_url}")
|
||||||
@@ -125,9 +131,9 @@ class BeatmapRawFetcher(BaseFetcher):
|
|||||||
|
|
||||||
# 所有 URL 都失败了
|
# 所有 URL 都失败了
|
||||||
error_msg = f"Failed to fetch beatmap {beatmap_id} from all sources"
|
error_msg = f"Failed to fetch beatmap {beatmap_id} from all sources"
|
||||||
if last_error:
|
if last_error and isinstance(last_error, NoBeatmapError):
|
||||||
raise HTTPError(error_msg) from last_error
|
raise last_error
|
||||||
raise HTTPError(error_msg)
|
raise HTTPError(error_msg) from last_error
|
||||||
|
|
||||||
async def get_or_fetch_beatmap_raw(self, redis: redis.Redis, beatmap_id: int) -> str:
|
async def get_or_fetch_beatmap_raw(self, redis: redis.Redis, beatmap_id: int) -> str:
|
||||||
from app.config import settings
|
from app.config import settings
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ from app.database.score import Score, calculate_playtime, calculate_user_pp
|
|||||||
from app.dependencies.database import engine, get_redis
|
from app.dependencies.database import engine, get_redis
|
||||||
from app.dependencies.fetcher import get_fetcher
|
from app.dependencies.fetcher import get_fetcher
|
||||||
from app.fetcher import Fetcher
|
from app.fetcher import Fetcher
|
||||||
|
from app.fetcher.beatmap_raw import NoBeatmapError
|
||||||
from app.log import log
|
from app.log import log
|
||||||
from app.models.mods import init_mods, init_ranked_mods, mod_to_save, mods_can_get_pp
|
from app.models.mods import init_mods, init_ranked_mods, mod_to_save, mods_can_get_pp
|
||||||
from app.models.score import GameMode, Rank
|
from app.models.score import GameMode, Rank
|
||||||
@@ -667,6 +668,17 @@ async def recalc_score_pp(
|
|||||||
continue
|
continue
|
||||||
attempts -= 1
|
attempts -= 1
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
|
except NoBeatmapError:
|
||||||
|
logger.warning(f"Beatmap raw not found for beatmap {score.beatmap_id}; cannot calculate pp")
|
||||||
|
return None
|
||||||
|
except CalculateError as exc:
|
||||||
|
attempts -= 1
|
||||||
|
logger.warning(
|
||||||
|
f"Calculation error for score {score.id} on "
|
||||||
|
f"beatmap {score.beatmap_id}: {exc}; attempts left: {attempts}"
|
||||||
|
)
|
||||||
|
await asyncio.sleep(2)
|
||||||
|
continue
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception(f"Failed to calculate pp for score {score.id} on beatmap {score.beatmap_id}")
|
logger.exception(f"Failed to calculate pp for score {score.id} on beatmap {score.beatmap_id}")
|
||||||
return None
|
return None
|
||||||
@@ -1125,6 +1137,9 @@ async def recalculate_beatmap_rating(
|
|||||||
else:
|
else:
|
||||||
logger.exception(f"Failed to calculate rating for beatmap {beatmap_id} after multiple attempts")
|
logger.exception(f"Failed to calculate rating for beatmap {beatmap_id} after multiple attempts")
|
||||||
return
|
return
|
||||||
|
except NoBeatmapError:
|
||||||
|
logger.error(f"Beatmap data for {beatmap_id} not found; cannot calculate rating")
|
||||||
|
return
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception(f"Unexpected error calculating rating for beatmap {beatmap_id}")
|
logger.exception(f"Unexpected error calculating rating for beatmap {beatmap_id}")
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user