Files
MoviePilot/docs/agent-execution.md
JontyLee f2918b9285 fix(scheduler): 让声明为不限时的协程任务预算真正生效
JobSpec.timeout_seconds 此前无法表达“显式不限时”:所有未声明预算的协程任务
一律补齐 SCHEDULER_JOB_TIMEOUT,订阅搜索队列因此被 3600 秒总时长判死,而它的
托管协程消费者无法靠取消收尾,只会把正常长轮次记成失败。现在收敛为三态语义
(正数为上限、0 为显式不限时、缺省继承默认),并修正 asyncio 超时异常 str()
为空导致的日志、系统通知与 SystemError 事件文本缺失。
2026-10-26 10:34:42 +08:00

4.7 KiB
Raw Permalink Blame History

智能助手执行优先策略

交互轮次从宿主 MoviePilotAgent.process 进入,到本轮推理及工具调用收口后结束。 网页、消息渠道、CLI 和兼容 API 的前台请求使用交互容量;自主定时任务与心跳保持后台归属, 即使配置了结果回传渠道也不会升级为交互轮次。

默认启用 AGENT_INTERACTIVE_PRIORITY=true。这是协作式资源隔离:正在运行的同步线程、 数据库事务和后台协程不会被抢占。主事件循环仍采用 asyncio 的协作调度, 因此同步代码阻塞事件循环、CPU 饱和、数据库锁竞争和模型网络延迟仍可能影响响应。

执行边界 交互容量 普通后台容量
ThreadHelper.submit 独立 4 线程 保留现有 CONF.threadpool
宿主 run_in_threadpool 当前事件循环共享 4 个 anyio 令牌 独立后台 limiter,容量跟随 anyio 默认配置(通常 40)
DatabaseWorker.run 独立 1 线程、运行及排队总计 8 项 保留 4 线程、总计 32 项默认值
Agent 同步工具 各能力域独立的交互桶 保留原能力域限额,供自主任务使用
APScheduler 自主 Agent 使用 agent 执行组,2 线程 其他任务使用原 default 组

以上容量按需启动工作线程,关闭时沿用各自生命周期 owner 的封口和收敛合同。 取消不会提前归还仍在执行的同步工具、线程调用或数据库事务的容量。 聊天持久化的全局写入准入也区分交互和后台;同一会话的写锁及单会话上限继续共享, 以免并发覆盖历史。DatabaseWorker.snapshot() 返回普通组,interactive_snapshot() 返回保留组; 数据库队列和执行指标包含两组的增减量。

执行归属通过上下文复制传入线程。moviepilot_api 的本机 HTTP 调用携带本进程随机登记的 临时执行凭据,由 ASGI 中间件恢复;普通自填请求头或已经结束的轮次无法取得优先级。 用户令牌与权限检查照常执行。子进程、外部 MCP 服务和插件自建线程池不受本策略控制。 框架同步鉴权与同步端点保留 anyio 默认 limiter,宿主后台线程调用不再消耗该组令牌; 框架自身的 HTTP 请求之间仍共用默认配额,不能保证在任意 HTTP 洪峰下立即响应。

后台避让

交互活跃时,新进入调度执行入口的非关键自动任务最多等待 AGENT_BACKGROUND_DEFER_SECONDS 秒,默认 30 秒,设为 0 禁用等待。 轮次结束后等待任务继续执行;持续对话超过预算时也会继续,避免后台任务饥饿。 期间保留原任务 generation、重入保护和协程句柄,不重复注册或补投任务。 调度器明确使用合并过期触发、单实例和无限 misfire 宽限,避免有限避让产生的排队 被默认一秒宽限误判为过期丢弃;任务自己的重入保护继续生效。 调度服务列表以“等待交互结束”显示正在避让的任务,API 的 execution_group 返回实际执行组。

Outbox 补偿、安全检查、数据库维护、运行时维护和手动专用任务不避让。 交互主动触发的同步调用不会等待自己结束;业务调度函数执行时会撤销继承的交互归属。 已有主循环同步入口沿用原调用合同,不在事件循环中同步等待。 避让只作用于新进入执行入口的任务,不会暂停或重放已开始的业务操作。

APScheduler 3 的标准线程池没有任意数值 priority 的调度能力。 这里通过独立执行组和实际准入等待实现隔离,不向 add_job 传入无效的优先级参数。 独立调度执行组仅隔离触发线程,协程仍回投到同一主循环。

超时

  • AGENT_LLM_TIMEOUT:单次根 Agent 模型请求总预算,默认 180 秒,覆盖流式与非流式生成 以及该请求的供应商重试;0 表示不限时。工具执行时间由原 LLM_TOOL_TIMEOUT 管理。
  • SCHEDULER_JOB_TIMEOUT:协程调度任务的默认执行预算,默认 3600 秒,等待避让不计入执行时间; 0 表示不限时。显式 JobSpec.timeout_seconds 优先于此默认值:正数是总时长上限,0 表示该任务显式不限时,缺省才继承此默认值。

超时通过协程取消收口,不能杀死同步线程或撤销已经发生的外部副作用。 数据库和线程调用仍等待实际操作收尾后释放容量,因而收尾时间可能超过超时预算。 超时后应先查询操作状态,再决定是否重试写入。

关闭 AGENT_INTERACTIVE_PRIORITY 可让 Agent 使用普通执行容量并停用避让;两项超时配置独立生效。 这些配置由部署环境或 app.env 提供,修改后重启生效。