mirror of
https://github.com/A-Minos/nonebot-plugin-tetris-stats.git
synced 2026-03-05 05:36:54 +08:00
✨ 为 IO Rank 添加重试机制
This commit is contained in:
@@ -14,6 +14,7 @@ from sqlalchemy import select
|
|||||||
from ...db import create_or_update_bind
|
from ...db import create_or_update_bind
|
||||||
from ...utils.exception import MessageFormatError, RequestError, WhatTheFuckError
|
from ...utils.exception import MessageFormatError, RequestError, WhatTheFuckError
|
||||||
from ...utils.request import splice_url
|
from ...utils.request import splice_url
|
||||||
|
from ...utils.retry import retry
|
||||||
from ...utils.typing import GameType
|
from ...utils.typing import GameType
|
||||||
from .. import Processor as ProcessorMeta
|
from .. import Processor as ProcessorMeta
|
||||||
from .cache import Cache
|
from .cache import Cache
|
||||||
@@ -153,10 +154,11 @@ class Processor(ProcessorMeta):
|
|||||||
|
|
||||||
|
|
||||||
@scheduler.scheduled_job('cron', hour='0,6,12,18', minute=0)
|
@scheduler.scheduled_job('cron', hour='0,6,12,18', minute=0)
|
||||||
|
@retry(exception_type=RequestError, delay=timedelta(minutes=15))
|
||||||
async def get_io_rank_data() -> None:
|
async def get_io_rank_data() -> None:
|
||||||
league_all: LeagueAll = parse_raw_as(LeagueAll, await Cache.get(splice_url([BASE_URL, 'users/lists/league/all']))) # type: ignore[arg-type]
|
league_all: LeagueAll = parse_raw_as(LeagueAll, await Cache.get(splice_url([BASE_URL, 'users/lists/league/all']))) # type: ignore[arg-type]
|
||||||
if isinstance(league_all, LeagueAllFailed):
|
if isinstance(league_all, LeagueAllFailed):
|
||||||
raise RequestError(f'用户Solo数据请求错误:\n{league_all.error}')
|
raise RequestError(f'排行榜数据请求错误:\n{league_all.error}')
|
||||||
|
|
||||||
def pps(user: LeagueAllUser) -> float:
|
def pps(user: LeagueAllUser) -> float:
|
||||||
return user.league.pps
|
return user.league.pps
|
||||||
@@ -212,8 +214,8 @@ async def get_io_rank_data() -> None:
|
|||||||
|
|
||||||
|
|
||||||
@driver.on_startup
|
@driver.on_startup
|
||||||
async def check_rank_data() -> None:
|
async def _() -> None:
|
||||||
async with get_session() as session:
|
async with get_session() as session:
|
||||||
latest_time = await session.scalar(select(IORank.create_time).order_by(IORank.id.desc()).limit(1))
|
latest_time = await session.scalar(select(IORank.create_time).order_by(IORank.id.desc()).limit(1))
|
||||||
if latest_time is None or datetime.now(tz=UTC) - latest_time.replace(tzinfo=UTC) > timedelta(hours=6):
|
if latest_time is None or datetime.now(tz=UTC) - latest_time.replace(tzinfo=UTC) > timedelta(hours=6):
|
||||||
await get_io_rank_data()
|
await get_io_rank_data()
|
||||||
|
|||||||
37
nonebot_plugin_tetris_stats/utils/retry.py
Normal file
37
nonebot_plugin_tetris_stats/utils/retry.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
from asyncio import sleep
|
||||||
|
from collections.abc import Awaitable, Callable
|
||||||
|
from datetime import timedelta
|
||||||
|
from functools import wraps
|
||||||
|
from typing import TypeVar, cast
|
||||||
|
|
||||||
|
from nonebot.log import logger
|
||||||
|
|
||||||
|
T = TypeVar('T')
|
||||||
|
|
||||||
|
|
||||||
|
def retry(
|
||||||
|
max_attempts: int = 3,
|
||||||
|
exception_type: type[BaseException] | tuple[type[BaseException], ...] = Exception,
|
||||||
|
delay: timedelta | None = None,
|
||||||
|
) -> Callable[[Callable[..., Awaitable[T]]], Callable[..., Awaitable[T]]]:
|
||||||
|
def decorator(func: Callable[..., Awaitable[T]]) -> Callable[..., Awaitable[T]]:
|
||||||
|
@wraps(func)
|
||||||
|
async def wrapper(*args, **kwargs) -> T: # noqa: ANN002, ANN003
|
||||||
|
attempts = 0
|
||||||
|
while attempts < max_attempts + 1:
|
||||||
|
try:
|
||||||
|
return await func(*args, **kwargs)
|
||||||
|
except exception_type as e: # noqa: PERF203
|
||||||
|
logger.exception(e)
|
||||||
|
attempts += 1
|
||||||
|
if attempts <= max_attempts:
|
||||||
|
if delay is not None:
|
||||||
|
await sleep(delay.total_seconds())
|
||||||
|
logger.debug(f'Retrying: {func.__name__} ({attempts}/{max_attempts})')
|
||||||
|
continue
|
||||||
|
raise
|
||||||
|
raise RuntimeError('Unexpectedly reached the end of the retry loop')
|
||||||
|
|
||||||
|
return cast(Callable[..., Awaitable[T]], wrapper)
|
||||||
|
|
||||||
|
return decorator
|
||||||
Reference in New Issue
Block a user