mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-30 04:27:40 +08:00
refactor: isolate agent task execution data boundary (#6433)
This commit is contained in:
+26
-12
@@ -79,7 +79,7 @@ from app.application.plugin.runtime import get_plugin_manager
|
||||
def _get_plugin_tools_revision() -> int:
|
||||
"""读取插件工具目录修订号,避免 Agent 编排依赖具体管理器类型。"""
|
||||
return get_plugin_manager().get_plugin_agent_tools_revision()
|
||||
from app.application.agentdata import get_agent_task_port
|
||||
from app.application.agenttask import get_agent_task_execution_service
|
||||
from app.application.agentdata import get_agent_user_port
|
||||
from app.application.messaging.chat import (
|
||||
get_configured_agent_chat_service,
|
||||
@@ -3504,6 +3504,8 @@ class AgentManager:
|
||||
self,
|
||||
task_id: int,
|
||||
trigger_source: str = "scheduled",
|
||||
scheduler_generation: int | None = None,
|
||||
remove_schedule: Callable[[int, int, str], bool] | None = None,
|
||||
) -> tuple[bool, str]:
|
||||
"""
|
||||
按持久化上下文唤醒 Agent 执行自主定时任务并向用户回传结果。
|
||||
@@ -3514,13 +3516,17 @@ class AgentManager:
|
||||
"""
|
||||
if not settings.AI_AGENT_ENABLE:
|
||||
return False, "AI Agent 未启用"
|
||||
oper = get_agent_task_port()
|
||||
task = oper.get(task_id)
|
||||
if not task or not task.enabled:
|
||||
return False, "Agent 定时任务不存在或已停用"
|
||||
run = oper.begin_run(task_id=task_id, trigger_source=trigger_source)
|
||||
if not run:
|
||||
return False, "Agent 定时任务当前不可执行"
|
||||
accepting_before_claim = self._accepting_tasks
|
||||
task_service = get_agent_task_execution_service()
|
||||
claim = await task_service.claim(
|
||||
task_id=task_id,
|
||||
trigger_source=trigger_source,
|
||||
scheduler_generation=scheduler_generation,
|
||||
remove_schedule=remove_schedule,
|
||||
)
|
||||
run = claim.run
|
||||
if run is None:
|
||||
return False, claim.rejection or "Agent 定时任务当前不可执行"
|
||||
|
||||
trigger_description = (
|
||||
"已手动触发" if run.trigger_source == "manual" else "已按计划触发"
|
||||
@@ -3558,7 +3564,14 @@ class AgentManager:
|
||||
raise
|
||||
except Exception as err:
|
||||
success = False
|
||||
result = f"Agent 定时任务执行失败:{str(err)}"
|
||||
error_message = str(err)
|
||||
if (
|
||||
accepting_before_claim
|
||||
and not self._accepting_tasks
|
||||
and error_message == "AgentManager 未运行或已关闭"
|
||||
):
|
||||
error_message = "AgentManager 已关闭"
|
||||
result = f"Agent 定时任务执行失败:{error_message}"
|
||||
logger.error(f"Agent 定时任务 {task_id} 执行失败: {str(err)}")
|
||||
await AgentChain().async_post_message(
|
||||
Message(
|
||||
@@ -3570,11 +3583,12 @@ class AgentManager:
|
||||
)
|
||||
)
|
||||
finally:
|
||||
oper.finish_run(
|
||||
run_id=run.run_id,
|
||||
await task_service.finalize(
|
||||
run,
|
||||
success=success,
|
||||
result=str(result or ""),
|
||||
disable_date_task=run.trigger_type == "date",
|
||||
scheduler_generation=scheduler_generation,
|
||||
remove_schedule=remove_schedule,
|
||||
)
|
||||
|
||||
return success, str(result or "任务执行完成")
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
"""Agent 自主定时任务执行的异步应用边界。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from typing import Protocol, TypeVar
|
||||
from uuid import uuid4
|
||||
|
||||
from app.application.database import AsyncDatabaseExecutor
|
||||
from app.runtime.execution import await_task_to_terminal
|
||||
from app.schemas.exception import DatabaseWorkerOverloadedError
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
SyncTransaction = Callable[[Callable[[object], T]], T]
|
||||
|
||||
|
||||
class AgentTaskRecord(Protocol):
|
||||
"""执行认领与终态判定所需的任务投影。"""
|
||||
|
||||
id: int
|
||||
enabled: bool
|
||||
last_run_id: str | None
|
||||
last_status: str
|
||||
|
||||
|
||||
class AgentTaskRunRecord(Protocol):
|
||||
"""执行期间需要脱离数据库会话持有的运行记录字段。"""
|
||||
|
||||
run_id: str
|
||||
task_id: int
|
||||
trigger_source: str
|
||||
name: str
|
||||
content: str
|
||||
trigger_type: str
|
||||
cron_expression: str | None
|
||||
run_at: str | None
|
||||
user_id: str
|
||||
username: str | None
|
||||
session_id: str
|
||||
|
||||
|
||||
class AgentTaskRepository(Protocol):
|
||||
"""AgentTask 执行用例使用的同步短事务仓储合同。"""
|
||||
|
||||
def get(self, task_id: int) -> AgentTaskRecord | None:
|
||||
"""读取任务当前投影。"""
|
||||
|
||||
def begin_run(
|
||||
self,
|
||||
task_id: int,
|
||||
trigger_source: str = "scheduled",
|
||||
*,
|
||||
run_id: str | None = None,
|
||||
) -> AgentTaskRunRecord | None:
|
||||
"""原子认领任务并创建运行快照。"""
|
||||
|
||||
def finish_run_outcome(
|
||||
self,
|
||||
run_id: str,
|
||||
success: bool,
|
||||
result: str,
|
||||
) -> AgentTaskFinishRecord:
|
||||
"""收口运行并返回事务确认的终态事实。"""
|
||||
|
||||
|
||||
class AgentTaskFinishRecord(Protocol):
|
||||
"""同步仓储返回的结构化运行终态。"""
|
||||
|
||||
run_finalized: bool
|
||||
task_projection_updated: bool
|
||||
date_task_disabled: bool
|
||||
|
||||
|
||||
AgentTaskRepositoryFactory = Callable[[object], AgentTaskRepository]
|
||||
AgentTaskScheduleRemover = Callable[[int, int, str], bool]
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class AgentTaskRunSnapshot:
|
||||
"""任务认领成功后可安全跨越数据库会话的执行快照。"""
|
||||
|
||||
run_id: str
|
||||
task_id: int
|
||||
trigger_source: str
|
||||
name: str
|
||||
content: str
|
||||
trigger_type: str
|
||||
cron_expression: str | None
|
||||
run_at: str | None
|
||||
user_id: str
|
||||
username: str | None
|
||||
session_id: str
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class AgentTaskClaim:
|
||||
"""任务认领结果;拒绝原因保持现有 Agent 用户提示合同。"""
|
||||
|
||||
run: AgentTaskRunSnapshot | None
|
||||
rejection: str | None = None
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class AgentTaskFinishOutcome:
|
||||
"""区分运行收口、任务投影更新与一次任务停用三个事实。"""
|
||||
|
||||
run_finalized: bool
|
||||
task_projection_updated: bool
|
||||
date_task_disabled: bool
|
||||
|
||||
|
||||
class AgentTaskExecutionService:
|
||||
"""通过有界数据库 worker 认领并收口一次 AgentTask 执行。"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
repository: AgentTaskRepositoryFactory,
|
||||
async_executor: AsyncDatabaseExecutor,
|
||||
sync_transaction: SyncTransaction,
|
||||
) -> None:
|
||||
"""保存同步仓储、事务和异步执行器。"""
|
||||
self._repository = repository
|
||||
self._async_executor = async_executor
|
||||
self._sync_transaction = sync_transaction
|
||||
|
||||
@staticmethod
|
||||
def _snapshot(run: AgentTaskRunRecord) -> AgentTaskRunSnapshot:
|
||||
"""在事务内复制运行字段,避免 ORM 对象越过会话边界。"""
|
||||
return AgentTaskRunSnapshot(
|
||||
run_id=run.run_id,
|
||||
task_id=run.task_id,
|
||||
trigger_source=run.trigger_source,
|
||||
name=run.name,
|
||||
content=run.content,
|
||||
trigger_type=run.trigger_type,
|
||||
cron_expression=run.cron_expression,
|
||||
run_at=run.run_at,
|
||||
user_id=run.user_id,
|
||||
username=run.username,
|
||||
session_id=run.session_id,
|
||||
)
|
||||
|
||||
async def claim(
|
||||
self,
|
||||
task_id: int,
|
||||
trigger_source: str = "scheduled",
|
||||
*,
|
||||
scheduler_generation: int | None = None,
|
||||
remove_schedule: AgentTaskScheduleRemover | None = None,
|
||||
) -> AgentTaskClaim:
|
||||
"""认领一次执行;取消发生在提交后时先补偿收口再传播取消。"""
|
||||
|
||||
run_id = uuid4().hex
|
||||
|
||||
def transaction(session: object) -> AgentTaskClaim:
|
||||
repository = self._repository(session)
|
||||
run = repository.begin_run(
|
||||
task_id=task_id,
|
||||
trigger_source=trigger_source,
|
||||
run_id=run_id,
|
||||
)
|
||||
if not run:
|
||||
task = repository.get(task_id)
|
||||
return AgentTaskClaim(
|
||||
run=None,
|
||||
rejection=(
|
||||
"Agent 定时任务不存在或已停用"
|
||||
if not task or not task.enabled
|
||||
else "Agent 定时任务当前不可执行"
|
||||
),
|
||||
)
|
||||
return AgentTaskClaim(run=self._snapshot(run))
|
||||
|
||||
async def claim_to_terminal() -> AgentTaskClaim:
|
||||
"""容量瞬时耗尽时保留本轮调度,直到认领取得 admission。"""
|
||||
while True:
|
||||
try:
|
||||
return await self._async_executor.run(
|
||||
lambda: self._sync_transaction(transaction)
|
||||
)
|
||||
except DatabaseWorkerOverloadedError:
|
||||
await asyncio.sleep(0.01)
|
||||
|
||||
claim_task = asyncio.create_task(claim_to_terminal())
|
||||
try:
|
||||
return await claim_task
|
||||
except asyncio.CancelledError as cancellation:
|
||||
finalize_task = asyncio.create_task(self._finalize(
|
||||
run_id=run_id,
|
||||
task_id=task_id,
|
||||
success=False,
|
||||
result="Agent 定时任务已取消",
|
||||
scheduler_generation=scheduler_generation,
|
||||
remove_schedule=remove_schedule,
|
||||
))
|
||||
await await_task_to_terminal(finalize_task)
|
||||
raise cancellation
|
||||
|
||||
async def finalize(
|
||||
self,
|
||||
run: AgentTaskRunSnapshot,
|
||||
*,
|
||||
success: bool,
|
||||
result: str,
|
||||
scheduler_generation: int | None = None,
|
||||
remove_schedule: AgentTaskScheduleRemover | None = None,
|
||||
) -> AgentTaskFinishOutcome:
|
||||
"""等待终态事务完成,并仅清理仍属于该 generation 的一次任务。"""
|
||||
|
||||
return await self._finalize(
|
||||
run_id=run.run_id,
|
||||
task_id=run.task_id,
|
||||
success=success,
|
||||
result=result,
|
||||
scheduler_generation=scheduler_generation,
|
||||
remove_schedule=remove_schedule,
|
||||
)
|
||||
|
||||
async def _finalize(
|
||||
self,
|
||||
*,
|
||||
run_id: str,
|
||||
task_id: int,
|
||||
success: bool,
|
||||
result: str,
|
||||
scheduler_generation: int | None,
|
||||
remove_schedule: AgentTaskScheduleRemover | None,
|
||||
) -> AgentTaskFinishOutcome:
|
||||
"""按稳定运行 ID 收口,供正常路径和取消补偿共享。"""
|
||||
|
||||
def transaction(session: object) -> AgentTaskFinishOutcome:
|
||||
repository = self._repository(session)
|
||||
outcome = repository.finish_run_outcome(
|
||||
run_id=run_id,
|
||||
success=success,
|
||||
result=result,
|
||||
)
|
||||
return AgentTaskFinishOutcome(
|
||||
run_finalized=outcome.run_finalized,
|
||||
task_projection_updated=outcome.task_projection_updated,
|
||||
date_task_disabled=outcome.date_task_disabled,
|
||||
)
|
||||
|
||||
async def finish_to_terminal() -> AgentTaskFinishOutcome:
|
||||
"""容量瞬时耗尽时保留 owner,直到收口取得 admission。"""
|
||||
while True:
|
||||
try:
|
||||
return await self._async_executor.run(
|
||||
lambda: self._sync_transaction(transaction)
|
||||
)
|
||||
except DatabaseWorkerOverloadedError:
|
||||
await asyncio.sleep(0.01)
|
||||
|
||||
finish_task = asyncio.create_task(finish_to_terminal())
|
||||
cancellation: asyncio.CancelledError | None = None
|
||||
try:
|
||||
outcome = await asyncio.shield(finish_task)
|
||||
except asyncio.CancelledError as error:
|
||||
cancellation = error
|
||||
outcome = await await_task_to_terminal(finish_task)
|
||||
|
||||
if (
|
||||
outcome.date_task_disabled
|
||||
and scheduler_generation is not None
|
||||
and remove_schedule is not None
|
||||
):
|
||||
remove_schedule(task_id, scheduler_generation, run_id)
|
||||
if cancellation is not None:
|
||||
raise cancellation
|
||||
return outcome
|
||||
|
||||
|
||||
_service: AgentTaskExecutionService | None = None
|
||||
|
||||
|
||||
def configure_agent_task_execution(service: AgentTaskExecutionService) -> None:
|
||||
"""由启动组合根登记 AgentTask 执行服务。"""
|
||||
global _service
|
||||
_service = service
|
||||
|
||||
|
||||
def get_agent_task_execution_service() -> AgentTaskExecutionService:
|
||||
"""返回已登记的 AgentTask 执行服务。"""
|
||||
if _service is None:
|
||||
raise RuntimeError("AgentTask 执行服务尚未配置")
|
||||
return _service
|
||||
@@ -1,9 +1,11 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from uuid import uuid4
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@@ -16,6 +18,15 @@ from app.db.models.agenttask import (
|
||||
from app.db.models.agenttaskrun import AgentTaskRun
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class AgentTaskFinishRecord:
|
||||
"""一次运行收口后由数据库事务确认的三个独立事实。"""
|
||||
|
||||
run_finalized: bool
|
||||
task_projection_updated: bool
|
||||
date_task_disabled: bool
|
||||
|
||||
|
||||
class AgentTaskOper(DbOper):
|
||||
"""
|
||||
Agent 自主定时任务管理。
|
||||
@@ -238,6 +249,62 @@ class AgentTaskOper(DbOper):
|
||||
)
|
||||
)
|
||||
|
||||
def finish_run_outcome(
|
||||
self,
|
||||
run_id: str,
|
||||
success: bool,
|
||||
result: str,
|
||||
) -> AgentTaskFinishRecord:
|
||||
"""收口运行,并返回当前事务实际更新的任务投影和停用事实。"""
|
||||
finished_at = self._now()
|
||||
normalized_result = (result or "")[:20000]
|
||||
expected_status = "success" if success else "failed"
|
||||
|
||||
def finalize(session: Session) -> AgentTaskFinishRecord:
|
||||
"""使用列查询绕过 ORM identity-map,读取刚写入的真实投影。"""
|
||||
finalized = AgentTaskRun.finish_run(
|
||||
session,
|
||||
run_id=run_id,
|
||||
success=success,
|
||||
result=normalized_result,
|
||||
finished_at=finished_at,
|
||||
disable_date_task=True,
|
||||
)
|
||||
run = session.execute(
|
||||
select(
|
||||
AgentTaskRun.task_id,
|
||||
AgentTaskRun.trigger_type,
|
||||
).where(AgentTaskRun.run_id == run_id)
|
||||
).mappings().first()
|
||||
task = None
|
||||
if run:
|
||||
task = session.execute(
|
||||
select(
|
||||
AgentTask.last_run_id,
|
||||
AgentTask.last_status,
|
||||
AgentTask.enabled,
|
||||
).where(AgentTask.id == run["task_id"])
|
||||
).mappings().first()
|
||||
projection_updated = bool(
|
||||
finalized
|
||||
and task
|
||||
and task["last_run_id"] == run_id
|
||||
and task["last_status"] == expected_status
|
||||
)
|
||||
return AgentTaskFinishRecord(
|
||||
run_finalized=finalized,
|
||||
task_projection_updated=projection_updated,
|
||||
date_task_disabled=bool(
|
||||
projection_updated
|
||||
and run
|
||||
and run["trigger_type"] == "date"
|
||||
and task
|
||||
and not task["enabled"]
|
||||
),
|
||||
)
|
||||
|
||||
return self._execute_sync_write(finalize)
|
||||
|
||||
def finish(
|
||||
self,
|
||||
task_id: int,
|
||||
|
||||
+51
-17
@@ -28,7 +28,7 @@ from app.chain.transfer import TransferChain
|
||||
from app.chain.workflow import WorkflowChain
|
||||
from app.runtime.config import global_vars
|
||||
from app.runtime.events import Event, eventmanager
|
||||
from app.db.oper.agenttask import AgentTaskOper
|
||||
from app.application.agentdata import get_agent_task_port
|
||||
from app.application.database import get_database_governance
|
||||
from app.application.outbox import dispatch_pending_outbox
|
||||
from app.application.plugin.runtime import get_plugin_manager
|
||||
@@ -1274,6 +1274,8 @@ class Scheduler(ConfigReloadMixin, metaclass=SingletonClass):
|
||||
func = job.get("func")
|
||||
if not func:
|
||||
return
|
||||
if func == self.execute_agent_task:
|
||||
kwargs.setdefault("scheduler_generation", generation)
|
||||
if self.__supports_progress_callback(func) and "progress_callback" not in kwargs:
|
||||
kwargs["progress_callback"] = self.__build_progress_callback(
|
||||
job_id=job_id, job=job
|
||||
@@ -1426,7 +1428,7 @@ class Scheduler(ConfigReloadMixin, metaclass=SingletonClass):
|
||||
"""
|
||||
按数据库当前状态注册所有启用的 Agent 自主定时任务。
|
||||
"""
|
||||
for task in AgentTaskOper().list(enabled=True):
|
||||
for task in get_agent_task_port().list(enabled=True):
|
||||
self.update_agent_task_job(task.id)
|
||||
|
||||
def _reconcile_agent_task_interruptions(self) -> None:
|
||||
@@ -1439,7 +1441,7 @@ class Scheduler(ConfigReloadMixin, metaclass=SingletonClass):
|
||||
with self._lock:
|
||||
if self._agent_task_interruptions_reconciled:
|
||||
return
|
||||
oper = AgentTaskOper()
|
||||
oper = get_agent_task_port()
|
||||
for task in oper.list():
|
||||
if task.last_status == "running":
|
||||
oper.mark_interrupted(
|
||||
@@ -1460,7 +1462,7 @@ class Scheduler(ConfigReloadMixin, metaclass=SingletonClass):
|
||||
"""
|
||||
config = get_scheduler_runtime_config()
|
||||
self.remove_agent_task_job(task_id)
|
||||
task = AgentTaskOper().get(task_id)
|
||||
task = get_agent_task_port().get(task_id)
|
||||
if (
|
||||
not config.ai_agent_enable
|
||||
or not task
|
||||
@@ -1496,6 +1498,8 @@ class Scheduler(ConfigReloadMixin, metaclass=SingletonClass):
|
||||
kwargs={"task_id": task_id},
|
||||
).to_runtime_state()
|
||||
self._assign_job_generation(job_id, job)
|
||||
job["_agent_task_run_id"] = task.last_run_id
|
||||
job["_agent_task_status"] = task.last_status
|
||||
self._jobs[job_id] = job
|
||||
self._jobs[job_id]["provider_name"] = "[Agent]"
|
||||
# 已开始的一次任务在重启后结果未知,只保留显式执行入口,不能按
|
||||
@@ -1531,6 +1535,31 @@ class Scheduler(ConfigReloadMixin, metaclass=SingletonClass):
|
||||
except JobLookupError:
|
||||
pass
|
||||
|
||||
def _remove_agent_task_job_generation(
|
||||
self,
|
||||
task_id: int,
|
||||
generation: int,
|
||||
run_id: str,
|
||||
) -> bool:
|
||||
"""移除本次执行或其运行中重载产生的 AgentTask 调度注册。"""
|
||||
job_id = self._get_agent_task_job_id(task_id)
|
||||
with self._lock:
|
||||
job = self._jobs.get(job_id)
|
||||
if job is None:
|
||||
return False
|
||||
if job.get("_generation", 0) != generation and not (
|
||||
job.get("_agent_task_run_id") == run_id
|
||||
and job.get("_agent_task_status") == "running"
|
||||
):
|
||||
return False
|
||||
self._jobs.pop(job_id, None)
|
||||
if self._scheduler:
|
||||
try:
|
||||
self._scheduler.remove_job(job_id)
|
||||
except JobLookupError:
|
||||
pass
|
||||
return True
|
||||
|
||||
def get_agent_task_next_run(self, task_id: int) -> Optional[str]:
|
||||
"""
|
||||
查询 Agent 自主定时任务的下一次执行时间。
|
||||
@@ -1546,7 +1575,7 @@ class Scheduler(ConfigReloadMixin, metaclass=SingletonClass):
|
||||
if next_run_time:
|
||||
return next_run_time.isoformat(timespec="seconds")
|
||||
|
||||
task = AgentTaskOper().get(task_id)
|
||||
task = get_agent_task_port().get(task_id)
|
||||
if not task or not task.enabled:
|
||||
return None
|
||||
if task.trigger_type == "date" and task.last_status == "interrupted":
|
||||
@@ -1572,6 +1601,7 @@ class Scheduler(ConfigReloadMixin, metaclass=SingletonClass):
|
||||
self,
|
||||
task_id: int,
|
||||
trigger_source: str = "scheduled",
|
||||
scheduler_generation: int | None = None,
|
||||
) -> tuple[bool, str]:
|
||||
"""
|
||||
唤醒 Agent 执行指定自主定时任务。
|
||||
@@ -1582,19 +1612,23 @@ class Scheduler(ConfigReloadMixin, metaclass=SingletonClass):
|
||||
"""
|
||||
from app.application.agent import get_running_agent_manager
|
||||
|
||||
try:
|
||||
manager = get_running_agent_manager()
|
||||
if manager is None:
|
||||
logger.warning("智能助手服务未运行,跳过 Agent 定时任务")
|
||||
return False, "智能助手服务未运行"
|
||||
return await manager.execute_scheduled_task(
|
||||
task_id,
|
||||
trigger_source=trigger_source,
|
||||
manager = get_running_agent_manager()
|
||||
if manager is None:
|
||||
logger.warning("智能助手服务未运行,跳过 Agent 定时任务")
|
||||
return False, "智能助手服务未运行"
|
||||
if scheduler_generation is None:
|
||||
job_id = self._get_agent_task_job_id(task_id)
|
||||
with self._lock:
|
||||
job = self._jobs.get(job_id)
|
||||
if job is not None:
|
||||
scheduler_generation = job.get("_generation", 0)
|
||||
kwargs: dict[str, Any] = {"trigger_source": trigger_source}
|
||||
if scheduler_generation is not None:
|
||||
kwargs.update(
|
||||
scheduler_generation=scheduler_generation,
|
||||
remove_schedule=self._remove_agent_task_job_generation,
|
||||
)
|
||||
finally:
|
||||
task = await AgentTaskOper().async_get(task_id)
|
||||
if task and task.trigger_type == "date" and not task.enabled:
|
||||
self.remove_agent_task_job(task_id)
|
||||
return await manager.execute_scheduled_task(task_id, **kwargs)
|
||||
|
||||
def init_plugin_jobs(self):
|
||||
"""
|
||||
|
||||
@@ -95,6 +95,10 @@ from app.application.site.query import SiteQueryService, configure_site_query_se
|
||||
from app.application.site.health import SiteHealthService, configure_site_health_service
|
||||
from app.application.workflow import WorkflowQueryService, configure_workflow_query
|
||||
from app.application.agentdata import configure_agent_data_ports
|
||||
from app.application.agenttask import (
|
||||
AgentTaskExecutionService,
|
||||
configure_agent_task_execution,
|
||||
)
|
||||
from app.api.data import ApiDataPorts, configure_api_data_runtime
|
||||
from app.application.subscription.write import configure_subscribe_writer
|
||||
from app.adapters.external.server import (
|
||||
@@ -831,6 +835,11 @@ async def init_modules() -> HostRuntime:
|
||||
workflow=lambda: WorkflowOper(),
|
||||
plugin_data=lambda: PluginDataOper(),
|
||||
)
|
||||
configure_agent_task_execution(AgentTaskExecutionService(
|
||||
repository=lambda session: AgentTaskOper(session),
|
||||
async_executor=database_worker,
|
||||
sync_transaction=transaction_runner.sync,
|
||||
))
|
||||
configure_subscribe_writer(
|
||||
lambda: TransactionalSubscribeWriter(
|
||||
sync_session=SessionFactory,
|
||||
|
||||
Reference in New Issue
Block a user