Merge pull request #2463 from InfinityPacer/main

处理链run_module支持raise_exception
This commit is contained in:
jxxghp 2024-07-01 10:33:55 +08:00 committed by GitHub
commit d4a9643f47
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 48 additions and 11 deletions

View File

@ -10,8 +10,7 @@ from ruamel.yaml import CommentedMap
from transmission_rpc import File
from app.core.config import settings
from app.core.context import Context
from app.core.context import MediaInfo, TorrentInfo
from app.core.context import Context, MediaInfo, TorrentInfo
from app.core.event import EventManager
from app.core.meta import MetaBase
from app.core.module import ModuleManager
@ -79,6 +78,7 @@ class ChainBase(metaclass=ABCMeta):
def run_module(self, method: str, *args, **kwargs) -> Any:
"""
运行包含该方法的所有模块然后返回结果
当kwargs包含命名参数raise_exception时如模块方法抛出异常且raise_exception为True则同步抛出异常
"""
def is_result_empty(ret):
@ -117,6 +117,8 @@ class ChainBase(metaclass=ABCMeta):
# 中止继续执行
break
except Exception as err:
if kwargs.get("raise_exception"):
raise
logger.error(
f"运行模块 {module_id}.{method} 出错:{str(err)}\n{traceback.format_exc()}")
self.messagehelper.put(title=f"{module_name}发生了错误",
@ -166,7 +168,8 @@ class ChainBase(metaclass=ABCMeta):
tmdbid=tmdbid, doubanid=doubanid, bangumiid=bangumiid, cache=cache)
def match_doubaninfo(self, name: str, imdbid: str = None,
mtype: MediaType = None, year: str = None, season: int = None) -> Optional[dict]:
mtype: MediaType = None, year: str = None, season: int = None,
raise_exception: bool = False) -> Optional[dict]:
"""
搜索和匹配豆瓣信息
:param name: 标题
@ -174,9 +177,10 @@ class ChainBase(metaclass=ABCMeta):
:param mtype: 类型
:param year: 年份
:param season:
:param raise_exception: 触发速率限制时是否抛出异常
"""
return self.run_module("match_doubaninfo", name=name, imdbid=imdbid,
mtype=mtype, year=year, season=season)
mtype=mtype, year=year, season=season, raise_exception=raise_exception)
def match_tmdbinfo(self, name: str, mtype: MediaType = None,
year: str = None, season: int = None) -> Optional[dict]:
@ -214,14 +218,15 @@ class ChainBase(metaclass=ABCMeta):
image_prefix=image_prefix, image_type=image_type,
season=season, episode=episode)
def douban_info(self, doubanid: str, mtype: MediaType = None) -> Optional[dict]:
def douban_info(self, doubanid: str, mtype: MediaType = None, raise_exception: bool = False) -> Optional[dict]:
"""
获取豆瓣信息
:param doubanid: 豆瓣ID
:param mtype: 媒体类型
:return: 豆瓣信息
:param raise_exception: 触发速率限制时是否抛出异常
"""
return self.run_module("douban_info", doubanid=doubanid, mtype=mtype)
return self.run_module("douban_info", doubanid=doubanid, mtype=mtype, raise_exception=raise_exception)
def tvdb_info(self, tvdbid: int) -> Optional[dict]:
"""

View File

@ -15,6 +15,7 @@ from app.modules.douban.apiv2 import DoubanApi
from app.modules.douban.douban_cache import DoubanCache
from app.modules.douban.scraper import DoubanScraper
from app.schemas import MediaPerson
from app.schemas.exception import APIRateLimitException
from app.schemas.types import MediaType
from app.utils.common import retry
from app.utils.http import RequestUtils
@ -147,11 +148,12 @@ class DoubanModule(_ModuleBase):
return None
def douban_info(self, doubanid: str, mtype: MediaType = None) -> Optional[dict]:
def douban_info(self, doubanid: str, mtype: MediaType = None, raise_exception: bool = True) -> Optional[dict]:
"""
获取豆瓣信息
:param doubanid: 豆瓣ID
:param mtype: 媒体类型
:param raise_exception: 触发速率限制时是否抛出异常
:return: 豆瓣信息
"""
"""
@ -427,7 +429,10 @@ class DoubanModule(_ModuleBase):
info = self.doubanapi.tv_detail(doubanid)
if info:
if "subject_ip_rate_limit" in info.get("msg", ""):
logger.warn(f"触发豆瓣IP速率限制错误信息{info} ...")
msg = f"触发豆瓣IP速率限制错误信息{info} ..."
logger.warn(msg)
if raise_exception:
raise APIRateLimitException(msg)
return None
celebrities = self.doubanapi.tv_celebrities(doubanid)
if celebrities:
@ -442,7 +447,10 @@ class DoubanModule(_ModuleBase):
info = self.doubanapi.movie_detail(doubanid)
if info:
if "subject_ip_rate_limit" in info.get("msg", ""):
logger.warn(f"触发豆瓣IP速率限制错误信息{info} ...")
msg = f"触发豆瓣IP速率限制错误信息{info} ..."
logger.warn(msg)
if raise_exception:
raise APIRateLimitException(msg)
return None
celebrities = self.doubanapi.movie_celebrities(doubanid)
if celebrities:
@ -601,7 +609,8 @@ class DoubanModule(_ModuleBase):
@retry(Exception, 5, 3, 3, logger=logger)
def match_doubaninfo(self, name: str, imdbid: str = None,
mtype: MediaType = None, year: str = None, season: int = None) -> dict:
mtype: MediaType = None, year: str = None, season: int = None,
raise_exception: bool = False) -> dict:
"""
搜索和匹配豆瓣信息
:param name: 名称
@ -609,6 +618,7 @@ class DoubanModule(_ModuleBase):
:param mtype: 类型
:param year: 年份
:param season: 季号
:param raise_exception: 触发速率限制时是否抛出异常
"""
if imdbid:
# 优先使用IMDBID查询
@ -629,7 +639,10 @@ class DoubanModule(_ModuleBase):
return {}
# 触发rate limit
if "search_access_rate_limit" in result.values():
logger.warn(f"触发豆瓣API速率限制错误信息{result} ...")
msg = f"触发豆瓣API速率限制错误信息{result} ..."
logger.warn(msg)
if raise_exception:
raise APIRateLimitException(msg)
return {}
if not result.get("items"):
logger.warn(f"未找到 {name} 的豆瓣信息")

View File

@ -15,3 +15,4 @@ from .tmdb import *
from .transfer import *
from .file import *
from .filetransfer import *
from .exception import *

14
app/schemas/exception.py Normal file
View File

@ -0,0 +1,14 @@
class ImmediateException(Exception):
"""
用于立即抛出异常而不重试的特殊异常类
当不希望使用重试机制时可以抛出此异常
"""
pass
class APIRateLimitException(ImmediateException):
"""
用于表示API速率限制的异常类
当API调用触发速率限制时可以抛出此异常以立即终止操作并报告错误
"""
pass

View File

@ -6,6 +6,8 @@ from typing import Any
from Crypto import Random
from Crypto.Cipher import AES
from app.schemas.exception import ImmediateException
def retry(ExceptionToCheck: Any,
tries: int = 3, delay: int = 3, backoff: int = 2, logger: Any = None):
@ -23,6 +25,8 @@ def retry(ExceptionToCheck: Any,
while mtries > 1:
try:
return f(*args, **kwargs)
except ImmediateException:
raise
except ExceptionToCheck as e:
msg = f"{str(e)}, {mdelay} 秒后重试 ..."
if logger: