mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-07 08:26:53 +08:00
fix(agent): isolate web and storage blocking I/O
This commit is contained in:
@@ -9,7 +9,7 @@ import uuid
|
||||
import warnings
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Callable, Dict, List, Optional
|
||||
from typing import Any, Awaitable, Callable, Dict, List, Optional
|
||||
|
||||
from fastapi.concurrency import run_in_threadpool
|
||||
from langchain.agents import create_agent
|
||||
@@ -2572,7 +2572,7 @@ class _MessageTask:
|
||||
allow_message_tools: bool = True
|
||||
output_callback: Optional[Callable[[str], None]] = None
|
||||
protected_output_callback: Optional[Callable[[str], Optional[bool]]] = None
|
||||
message_callback: Optional[Callable[[Any], None]] = None
|
||||
message_callback: Optional[Callable[[Any], Awaitable[None] | None]] = None
|
||||
agent_factory: Optional[Callable[..., MoviePilotAgent]] = None
|
||||
agent_setup: Optional[Callable[[MoviePilotAgent], None]] = None
|
||||
completion_future: Optional[asyncio.Future] = None
|
||||
@@ -2834,7 +2834,7 @@ class AgentManager:
|
||||
allow_message_tools: bool = True,
|
||||
output_callback: Optional[Callable[[str], None]] = None,
|
||||
protected_output_callback: Optional[Callable[[str], Optional[bool]]] = None,
|
||||
message_callback: Optional[Callable[[Any], None]] = None,
|
||||
message_callback: Optional[Callable[[Any], Awaitable[None] | None]] = None,
|
||||
agent_factory: Optional[Callable[..., MoviePilotAgent]] = None,
|
||||
agent_setup: Optional[Callable[[MoviePilotAgent], None]] = None,
|
||||
wait_for_completion: bool = False,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import asyncio
|
||||
import inspect
|
||||
import json
|
||||
import threading
|
||||
from abc import ABCMeta, abstractmethod
|
||||
@@ -646,7 +647,9 @@ class MoviePilotTool(BaseTool, metaclass=ABCMeta):
|
||||
self._channel == NotificationChannel.WebAgent.value
|
||||
and callable(callback)
|
||||
):
|
||||
callback(message)
|
||||
callback_result = callback(message)
|
||||
if inspect.isawaitable(callback_result):
|
||||
await callback_result
|
||||
return
|
||||
|
||||
if not self._channel or not self._source:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""删除整理历史记录工具"""
|
||||
|
||||
import asyncio
|
||||
from typing import Optional, Type
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -20,6 +21,14 @@ class DeleteTransferHistoryInput(BaseModel):
|
||||
)
|
||||
|
||||
|
||||
def _delete_history_destination_file(fileitem: FileItem) -> tuple[bool, bool]:
|
||||
"""在存储 worker 内完成旧目标检查和删除,保持历史删除前的顺序。"""
|
||||
storage_chain = StorageChain()
|
||||
if not storage_chain.exists(fileitem):
|
||||
return False, False
|
||||
return True, bool(storage_chain.delete_media_file(fileitem))
|
||||
|
||||
|
||||
class DeleteTransferHistoryTool(MoviePilotTool):
|
||||
name: str = "delete_transfer_history"
|
||||
tags: list[str] = [
|
||||
@@ -55,9 +64,21 @@ class DeleteTransferHistoryTool(MoviePilotTool):
|
||||
deleted_dest = False
|
||||
if history.dest_fileitem and not (history.status and history.mode == "move"):
|
||||
dest_fileitem = FileItem(**history.dest_fileitem)
|
||||
storage_chain = StorageChain()
|
||||
if storage_chain.exists(dest_fileitem):
|
||||
if not storage_chain.delete_media_file(dest_fileitem):
|
||||
try:
|
||||
destination_exists, destination_deleted = await self.run_blocking(
|
||||
"storage",
|
||||
_delete_history_destination_file,
|
||||
dest_fileitem,
|
||||
)
|
||||
except asyncio.CancelledError:
|
||||
logger.warning(
|
||||
"删除整理历史的旧媒体文件等待已取消,底层文件操作可能仍在继续,"
|
||||
"请确认实际状态后再重试,历史记录尚未删除,path=%s",
|
||||
dest_fileitem.path,
|
||||
)
|
||||
raise
|
||||
if destination_exists:
|
||||
if not destination_deleted:
|
||||
return f"错误:旧媒体库文件删除失败,路径={dest_fileitem.path}"
|
||||
deleted_dest = True
|
||||
await transferhis.async_delete(history_id)
|
||||
|
||||
Reference in New Issue
Block a user