refactor: 推进后端分层架构治理

This commit is contained in:
jxxghp
2026-08-18 00:29:14 +08:00
parent 5d0bacabd5
commit 5128ae9e1e
363 changed files with 34179 additions and 6019 deletions
+159 -2
View File
@@ -1,4 +1,6 @@
from typing import Any, Dict, Optional, Union
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Callable, Dict, Optional, Protocol, Union
from app.domain.context import MediaInfo, MusicInfo
from app.schemas.media import resolve_media_identity
@@ -9,7 +11,8 @@ from app.runtime.config import settings
from app.db.models.transferhistory import TransferHistory
from app.db.oper.transferhistory import TransferHistoryOper
from app.runtime.log import logger
from app.schemas import FileItem, TransferInfo
from app.schemas.workflow import FileItem
from app.schemas.transfer import TransferInfo
from app.schemas.types import MUSIC_ENTITY_RECORDING
# 失败重试次数的合法区间。下界为 1:一次瞬时故障(网络抖动、TMDB 瞬断、移动失败)
@@ -25,6 +28,160 @@ FAILED_RETRY_TTL = 24 * 3600
_failed_retry_counts = TTLCache(region="transfer_failed_retry", maxsize=5000, ttl=FAILED_RETRY_TTL)
@dataclass(frozen=True, slots=True)
class HistoryMutationResult:
"""描述历史记录维护操作是否成功及兼容提示。"""
success: bool
message: str = ""
class DownloadHistoryMutationRepository(Protocol):
"""下载历史删除用例需要的最小持久化端口。"""
def stage_delete_history(self, history_id: int) -> None:
"""暂存下载历史删除。"""
...
class TransferHistoryMutationRepository(Protocol):
"""整理历史删除与清理用例需要的最小持久化端口。"""
def get(self, history_id: int) -> Optional[Any]:
"""读取整理历史。"""
...
def stage_delete(self, history_id: int) -> None:
"""暂存整理历史删除。"""
...
def stage_truncate(self) -> None:
"""暂存全部整理历史删除。"""
...
class DownloadFileMutationRepository(Protocol):
"""整理历史删除时关联下载文件状态更新端口。"""
def stage_delete_file_by_fullpath(self, fullpath: str) -> None:
"""暂存下载文件删除状态。"""
...
class HistoryUnitOfWork(Protocol):
"""同步历史维护用例使用的事务端口。"""
def commit(self) -> None:
"""提交当前事务。"""
...
def rollback(self) -> None:
"""回滚当前事务。"""
...
class DownloadHistoryMutationCommand:
"""统一提交下载历史删除,避免 API 直接持有数据库事务。"""
def __init__(
self,
*,
repository: DownloadHistoryMutationRepository,
unit_of_work: HistoryUnitOfWork,
) -> None:
"""保存下载历史持久化和事务端口。"""
self._repository = repository
self._unit_of_work = unit_of_work
def delete(self, history_id: int) -> HistoryMutationResult:
"""暂存并提交单条下载历史删除。"""
self._repository.stage_delete_history(history_id)
self._commit()
return HistoryMutationResult(True)
def _commit(self) -> None:
"""提交事务,失败时回滚。"""
try:
self._unit_of_work.commit()
except Exception:
self._unit_of_work.rollback()
raise
class TransferHistoryMutationCommand:
"""协调整理历史、关联文件状态和外部存储删除。"""
def __init__(
self,
*,
repository: TransferHistoryMutationRepository,
download_repository: DownloadFileMutationRepository,
unit_of_work: HistoryUnitOfWork,
file_item_factory: Callable[[dict], Any],
delete_media_file: Callable[[Any], bool],
publish_download_file_deleted: Callable[[dict], None],
clear_failures: Callable[[Optional[str], Optional[str]], None],
) -> None:
"""保存历史事务、存储删除、事件和失败状态清理端口。"""
self._repository = repository
self._download_repository = download_repository
self._unit_of_work = unit_of_work
self._file_item_factory = file_item_factory
self._delete_media_file = delete_media_file
self._publish_download_file_deleted = publish_download_file_deleted
self._clear_failures = clear_failures
def delete(
self,
history_id: int,
*,
delete_source: bool = False,
delete_destination: bool = False,
) -> HistoryMutationResult:
"""删除整理记录,并保持源文件失败时不提交数据库变更。"""
history = self._repository.get(history_id)
if not history:
return HistoryMutationResult(False, "记录不存在")
if delete_destination and history.dest_fileitem:
destination = self._file_item_factory(history.dest_fileitem)
self._delete_media_file(destination)
source_deleted = False
if delete_source and history.src_fileitem:
source = self._file_item_factory(history.src_fileitem)
if not self._delete_media_file(source):
return HistoryMutationResult(False, f"{source.path} 删除失败")
self._download_repository.stage_delete_file_by_fullpath(
Path(source.path).as_posix()
)
source_deleted = True
self._repository.stage_delete(history_id)
self._commit()
if source_deleted:
self._publish_download_file_deleted({
"src": history.src,
"hash": history.download_hash,
})
self._clear_failures(history.src, history.src_storage)
return HistoryMutationResult(True)
def truncate(self) -> HistoryMutationResult:
"""在单一事务中清空全部整理历史。"""
self._repository.stage_truncate()
self._commit()
return HistoryMutationResult(True)
def _commit(self) -> None:
"""提交历史事务,失败时回滚且不发布事件或清缓存。"""
try:
self._unit_of_work.commit()
except Exception:
self._unit_of_work.rollback()
raise
class HistoryGateAction:
"""
整理历史查重闸的判定结果。