mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-04 23:17:20 +08:00
fix(subscription): isolate statistic report failures
This commit is contained in:
@@ -13,6 +13,7 @@ from app.application.outbox import (
|
||||
SyncOutboxTransaction,
|
||||
SyncUnitOfWork,
|
||||
)
|
||||
from app.runtime.log import logger
|
||||
|
||||
|
||||
class SubscriptionCompletionRepository(Protocol):
|
||||
@@ -116,9 +117,15 @@ class CompleteSubscriptionCommand:
|
||||
self._publish(event_payload)
|
||||
self._complete_sync_delivery(event_key)
|
||||
if self._claim_sync_delivery(report_key):
|
||||
if report(report_payload["subscribe_info"]) is False:
|
||||
raise RuntimeError("订阅完成统计上报未确认")
|
||||
self._complete_sync_delivery(report_key)
|
||||
try:
|
||||
report_delivered = report(report_payload["subscribe_info"])
|
||||
except Exception as error:
|
||||
logger.warning(f"订阅完成统计上报失败,将由后台重试:{error}")
|
||||
else:
|
||||
if report_delivered is False:
|
||||
logger.warning("订阅完成统计上报未确认,将由后台重试")
|
||||
else:
|
||||
self._complete_sync_delivery(report_key)
|
||||
|
||||
def _claim_sync_delivery(self, event_key: str) -> bool:
|
||||
"""在同步副作用前取得 lease,已由恢复投递接管时跳过直投。"""
|
||||
|
||||
@@ -14,6 +14,7 @@ from app.application.outbox import (
|
||||
SyncUnitOfWork,
|
||||
SUBSCRIBE_DELETED_TOPIC,
|
||||
)
|
||||
from app.runtime.log import logger
|
||||
from app.schemas.event import SubscribeDeletedEventData
|
||||
|
||||
|
||||
@@ -153,16 +154,20 @@ class DeleteSubscribeCommand:
|
||||
)
|
||||
# 上报适配器会自行白名单过滤公开字段;传完整删除前快照可保留音乐实体维度,
|
||||
# 避免 Agent 与 API 入口收敛后丢失 music_type / total_tracks。
|
||||
report_result = self._report_deleted(effects.report_payload)
|
||||
if inspect.isawaitable(report_result):
|
||||
report_result = await report_result
|
||||
if report_result is False:
|
||||
raise RuntimeError("订阅删除统计上报未确认")
|
||||
if self._outbox:
|
||||
await self._outbox.complete_by_event_key(
|
||||
effects.report_intent.event_key,
|
||||
datetime.now(timezone.utc),
|
||||
)
|
||||
try:
|
||||
report_result = self._report_deleted(effects.report_payload)
|
||||
if inspect.isawaitable(report_result):
|
||||
report_result = await report_result
|
||||
except Exception as error:
|
||||
logger.warning(f"订阅删除统计上报失败,将由后台重试:{error}")
|
||||
else:
|
||||
if report_result is False:
|
||||
logger.warning("订阅删除统计上报未确认,将由后台重试")
|
||||
elif self._outbox:
|
||||
await self._outbox.complete_by_event_key(
|
||||
effects.report_intent.event_key,
|
||||
datetime.now(timezone.utc),
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
@@ -216,13 +221,18 @@ class SyncDeleteSubscribeCommand:
|
||||
effects.event_intent.event_key,
|
||||
datetime.now(timezone.utc),
|
||||
)
|
||||
if self._report_deleted(effects.report_payload) is False:
|
||||
raise RuntimeError("订阅删除统计上报未确认")
|
||||
if self._outbox:
|
||||
self._outbox.complete_by_event_key(
|
||||
effects.report_intent.event_key,
|
||||
datetime.now(timezone.utc),
|
||||
)
|
||||
try:
|
||||
report_result = self._report_deleted(effects.report_payload)
|
||||
except Exception as error:
|
||||
logger.warning(f"订阅删除统计上报失败,将由后台重试:{error}")
|
||||
else:
|
||||
if report_result is False:
|
||||
logger.warning("订阅删除统计上报未确认,将由后台重试")
|
||||
elif self._outbox:
|
||||
self._outbox.complete_by_event_key(
|
||||
effects.report_intent.event_key,
|
||||
datetime.now(timezone.utc),
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ from app.schemas.types import MUSIC_ENTITY_ALBUM, MediaType
|
||||
# 而后续按身份去重也会失效,所以必须在查询与建模之前短路
|
||||
INCOMPLETE_IDENTITY = (0, "媒体身份不完整")
|
||||
|
||||
AfterCommitEffect = Callable[[int], None]
|
||||
AsyncAfterCommitEffect = Callable[[int], Awaitable[None]]
|
||||
AfterCommitEffect = Callable[[int], bool | None]
|
||||
AsyncAfterCommitEffect = Callable[[int], Awaitable[bool | None]]
|
||||
|
||||
|
||||
class SubscriptionOutboxStager(Protocol):
|
||||
@@ -57,7 +57,7 @@ class SubscribeWriter(Protocol):
|
||||
after_commit: Optional[AfterCommitEffect] = None,
|
||||
notification: Mapping[str, object] | None = None,
|
||||
) -> Tuple[int, str]:
|
||||
"""同步新增订阅,并在事务成功后执行外部副作用。"""
|
||||
"""同步新增订阅;提交后回调返回 False 时保留统计 intent 待重试。"""
|
||||
|
||||
async def async_add(
|
||||
self,
|
||||
@@ -67,7 +67,7 @@ class SubscribeWriter(Protocol):
|
||||
after_commit: Optional[AsyncAfterCommitEffect] = None,
|
||||
notification: Mapping[str, object] | None = None,
|
||||
) -> Tuple[int, str]:
|
||||
"""异步新增订阅,并在事务成功后执行外部副作用。"""
|
||||
"""异步新增订阅;提交后回调返回 False 时保留统计 intent 待重试。"""
|
||||
|
||||
|
||||
class StagedSubscription(Protocol):
|
||||
@@ -382,7 +382,7 @@ def add_subscribe(
|
||||
|
||||
:param mediainfo: 识别结果
|
||||
:param subscribe_oper: 复用的订阅操作对象,未传时由启动组合根提供
|
||||
:param after_commit: 数据提交后执行的消息、事件或上报编排
|
||||
:param after_commit: 提交后副作用编排;返回 False 表示统计 intent 等待重试
|
||||
:param kwargs: 订阅设置;owner_scope 为真时按用户名限定查重范围
|
||||
:return: (订阅 ID, 结果说明);ID 为 0 表示未新增
|
||||
"""
|
||||
@@ -420,7 +420,7 @@ async def async_add_subscribe(
|
||||
|
||||
:param mediainfo: 识别结果
|
||||
:param subscribe_oper: 复用的订阅操作对象,未传时由启动组合根提供
|
||||
:param after_commit: 数据提交后执行的异步消息、事件或上报编排
|
||||
:param after_commit: 异步提交后副作用编排;返回 False 表示统计 intent 等待重试
|
||||
:param kwargs: 订阅设置;owner_scope 为真时按用户名限定查重范围
|
||||
:return: (订阅 ID, 结果说明);ID 为 0 表示未新增
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user