跳到主要内容
非官方简体中文翻译,内容版权归 Mastra 所有,遵循 Apache-2.0 许可。

持久化 agents

新增于: @mastra/core@1.45.0

beta

在 API 稳定之前,可能在不提升主版本号的情况下发生破坏性变更。

持久化 agent 包装一个常规的 Agent,使 agentic 循环在 workflow 内运行。事件通过 PubSub流动,这意味着客户端可以断开并重新连接而不丢失 chunk。运行状态会被持久化,因此能在进程重启后保留。

何时使用持久化 agents
何时使用持久化 agents的直接链接

以下任一情况适用时,请使用持久化 agent:

  • 客户端可能在流中途断开并重连(移动端、不稳定网络、长时间运行调用)。
  • agentic 循环可能超出单个 HTTP 请求的生命周期(后台研究、多步骤工具使用)。
  • 你需要 observe/reconnect API,让第二个客户端接上第一个客户端启动的流。
  • 你希望使用 Inngest 驱动的执行,获得步骤记忆化、重试和监控。

对于客户端保持连接的短生命周期、请求作用域调用,带 stream() 或 generate() 的常规 Agent 更简单。

快速开始
快速开始的直接链接

使用 @mastra/core/agent/durable 中的 createDurableAgent() 包装现有 agent:

src/mastra/agents/researcher.ts
import { Agent } from '@mastra/core/agent'
import { createDurableAgent } from '@mastra/core/agent/durable'

const agent = new Agent({
id: 'researcher',
name: 'Researcher',
instructions: 'You research topics thoroughly.',
model: 'openai/gpt-5.6-sol',
})

export const durableResearcher = createDurableAgent({ agent })

将持久化 agent 注册到 Mastra 并调用 stream():

src/mastra/index.ts
import { Mastra } from '@mastra/core'
import { durableResearcher } from './agents/researcher'

const mastra = new Mastra({
agents: { durableResearcher },
})

const { output, runId, cleanup } = await durableResearcher.stream(
'Research quantum computing advances in 2025',
)

for await (const chunk of output.fullStream) {
// Process each chunk as it arrives
}

// Release PubSub subscriptions and clear the run from the registry.
// If you skip this, an automatic cleanup timer fires after the stream ends.
cleanup()

返回的 runId 标识该执行。将其传给 observe() 即可从另一个客户端重新连接。完整配置和方法 API 请参阅 DurableAgent 参考。

工作原理
工作原理的直接链接

持久化 agent 在常规 agent 之上增加了三层:

  1. Workflow 执行:stream() 将消息和选项序列化为 workflow 输入,然后在持久化 workflow 内触发 agentic 循环。该 workflow 运行与 Agent.stream() 相同的循环,但每一步都可以被记忆化和重放。

  2. PubSub 流式传输:循环将 chunk 发布到以运行 ID 为键的 PubSub topic。调用方订阅该 topic,并将 chunk 管道传输到 ReadableStream,同时缓存会重放断开期间错过的任何 chunk。

  3. 缓存层:可选缓存(默认内存中,生产环境可用 Redis 或其他后端)存储已发布事件,以便迟到订阅者能够追赶。

执行变体
执行变体的直接链接

Mastra 提供三个工厂函数来生成持久化 agents。它们的区别在于 workflow 的执行方式:

工厂函数包最适合
createDurableAgent()@mastra/core本地开发和单进程服务器。你获得可直接等待的流。
createEventedAgent()@mastra/core后台执行。workflow 在不阻塞的情况下启动,你通过 PubSub 消费 chunk。
createInngestAgent()@mastra/inngest生产部署。Inngest 增加步骤记忆化、重试和监控仪表板。

三者都返回一个对象,你可以像常规 agent 一样注册到 Mastra。createDurableAgent() 和 createEventedAgent() 返回扩展 Agent 的类实例。createInngestAgent() 返回一个由 Proxy 支持的对象,将 Agent 方法转发到底层 agent。当 signal 唤醒空闲 thread 时,三者都会用持久化的 stream() 启动该运行。sendSignal() 和 sendNotificationSignal() 都以此方式工作。

使用 createDurableAgent() 的进程内执行
使用-createdurableagent-的进程内执行的直接链接

包装你的 agent 并调用 stream()。你会在同一进程中得到 DurableAgentStreamResult。无需外部基础设施,因此这是最快的入门方式:

src/mastra/agents/durable.ts
import { Agent } from '@mastra/core/agent'
import { createDurableAgent } from '@mastra/core/agent/durable'

const agent = new Agent({
id: 'helper',
instructions: 'You are a helpful assistant.',
model: 'openai/gpt-5.6-sol',
})

export const durableHelper = createDurableAgent({ agent })

使用 createEventedAgent() 的即发即忘
使用-createeventedagent-的即发即忘的直接链接

workflow 在后台启动,不阻塞调用方。你仍会通过 PubSub 接收 chunk,因此 stream() 会返回一个可消费的结果。触发运行的 HTTP 处理程序无需等待 workflow 完成:

src/mastra/agents/evented.ts
import { Agent } from '@mastra/core/agent'
import { createEventedAgent } from '@mastra/core/agent/durable'

const agent = new Agent({
id: 'writer',
instructions: 'You write articles.',
model: 'openai/gpt-5.6-sol',
})

export const eventedWriter = createEventedAgent({ agent })

通过 API 创建的已存储 agents
通过 API 创建的已存储 agents的直接链接

使用 createStoredAgent()创建的 agents 可通过 agent 配置上的 durable 字段选择加入。服务器在补水(hydrate)该 agent 时用 createDurableAgent() 包装它,因此无需部署代码:

await mastraClient.createStoredAgent({
id: 'helper',
name: 'Helper',
instructions: 'You are a helpful assistant.',
model: { provider: 'openai', name: 'gpt-5' },
durable: true,
})

durable 也接受 { maxSteps, cleanupTimeoutMs }。这里只接受可序列化的选项,因此 API 创建的 agent 的快照持久化遵循服务器的 recovery.durableAgents 设置。缓存和 pubsub 继承自服务器的 Mastra 实例,因此若需要跨副本的持久性,请在那里配置分布式后端。自动恢复仍需通过代码中的 recovery.durableAgents 配置。

使用 createInngestAgent() 的 Inngest 驱动执行
使用-createinngestagent-的-inngest-驱动执行的直接链接

在 Inngest 平台上运行 workflow。每次工具调用都会成为可记忆化的步骤,Inngest 可以独立重试,并且你会获得用于监控运行的仪表板:

src/mastra/agents/inngest.ts
import { Agent } from '@mastra/core/agent'
import { createInngestAgent } from '@mastra/inngest'
import { Inngest } from 'inngest'

const inngest = new Inngest({ id: 'my-app' })

const agent = new Agent({
id: 'analyst',
instructions: 'You analyze data.',
model: 'openai/gpt-5.6-sol',
})

export const inngestAnalyst = createInngestAgent({ agent, inngest })

完整 API(包括 PubSub 和缓存配置等 Inngest 特定选项)请参阅 createInngestAgent() 参考。

可恢复流
可恢复流的直接链接

持久化 agents 通过 PubSub 和事件缓存支持可恢复流。当客户端在流中途断开时,缓存会继续存储事件。同一客户端可以通过使用 runId 调用 observe() 重新连接:

src/server/reconnect.ts
const { output } = await durableResearcher.observe(runId)

for await (const chunk of output.fullStream) {
// Chunks from the run, including any missed while disconnected
}

不带 offset 调用 observe(runId) 是受支持的通用重连流程。它会先重放所有可用缓存事件,再投递实时事件。对于已完成的运行,观察会重放保留的事件后关闭。如果运行未知或其历史已被清除且没有实时运行剩余,观察会在没有事件的情况下关闭。此时 HTTP observe 端点返回一个空的、已关闭的流,而不是等待其空闲超时。

可选的 offset 是从零开始且包含端点的 PubSub 事件索引,而不是 chunk 编号,公共流不会暴露它。如果 offset 跳过了较早的文本 delta,聚合文本会不完整,结构化输出可能无效。在支持数字 offset 的传输上,超出最高保留索引的 offset 也会跳过索引更低的实时事件。实时运行会等待已发布索引达到所请求的 offset。带保留终止事件的已完成运行即使 offset 跳过了所有事件也会关闭。完整的 offset 和传输行为请参阅 observe(runId, options?)。

重放不是永久的执行归档。事件仅在清理清除它们或缓存移除它们之前可用。workflow 快照无法重建已清除的流事件,禁用缓存会阻止历史重放。

观察并不拥有该运行。当循环结束,或你通过 break、return 或错误提前离开时,观察者会取消订阅,而运行会继续供其他观察者使用。若要从循环外停止观察(例如客户端断开时),请调用 detach():

src/server/reconnect.ts
const { output, detach } = await durableResearcher.observe(runId)

request.signal.addEventListener('abort', detach, { once: true })

if (request.signal.aborted) detach()

for await (const chunk of output.fullStream) {
// Stops when the run finishes or the client disconnects
}

如果你传入 idleTimeoutMs,且在该时长内没有 chunk 到达,Mastra 会在你提供 isAlive 时检查它。如果 isAlive 返回 true 或抛出异常,计时器会重启,流保持打开。否则流会以错误 chunk 结束并分离观察者。只有当 isAlive 返回 false 时,运行本身才会被清理。

createDurableAgent() 和 createEventedAgent() 默认使用内存缓存,这意味着可恢复流在单个进程内有效。若需跨进程或副本重连,请在生产者与观察者之间共享重放缓存、PubSub 传输和运行存储。共享传输能投递实时事件,但无法恢复仅存在于另一个进程缓存中的事件。请配置持久化缓存后端(例如 Redis),使保留的事件能在进程重启后保留:

src/mastra/agents/durable-with-cache.ts
import { createDurableAgent } from '@mastra/core/agent/durable'
import { RedisServerCache } from '@mastra/redis'
import Redis from 'ioredis'

const cache = new RedisServerCache({ client: new Redis('redis://localhost:6379') })

export const durableAgent = createDurableAgent({
agent,
cache,
})

createInngestAgent() 默认不启用缓存。传入 cache 选项,或将 agent 注册到已配置 serverCache 的 Mastra 实例,以启用可恢复流。

对于已缓存的 topics,每个已发布事件在实时投递之前都会记录到缓存中,因此发布延迟受缓存往返时间限制。如果缓存写入失败,事件仍会实时投递,但无法重放。@mastra/redis 和 @mastra/valkey 使用 Lua 脚本在单次往返中记录每个事件。当客户端没有 evalScript 或 Redis Cluster 拒绝多键脚本时,@mastra/redis 会回退到单独的命令。每次运行的 workflow 监视事件(workflow.events.v2.*)永远不会被缓存。如果缓存位于远程(例如另一个区域)且你不需要恢复某个 topic,请使用 shouldCache 让该 topic 直接发布:

src/mastra/agents/durable-hot-topics.ts
export const durableAgent = createDurableAgent({
agent,
cache,
// Skip the replay cache for the per-chunk stream topic; other topics stay resumable.
shouldCache: topic => !topic.startsWith('agent.stream.'),
})

与后台任务一起流式传输
与后台任务一起流式传输的直接链接

持久化 agents 支持与常规 agents 相同的 untilIdle 选项。设置 untilIdle 后,stream() 会跨后台任务延续保持连接打开,直到 agent 空闲:

src/mastra/run.ts
const { output, cleanup } = await durableAgent.stream('Research and summarize the topic', {
untilIdle: true,
memory: { thread: 'thread-1', resource: 'user-1' },
})

for await (const chunk of output.fullStream) {
// Chunks from the initial turn AND any follow-up turns triggered by
// background task completions
}

cleanup()

传入 { maxIdleMs } 可自定义空闲超时(默认 5 分钟):

await durableAgent.stream('Research topic', {
untilIdle: { maxIdleMs: 30_000 },
memory: { thread: 'thread-1', resource: 'user-1' },
})

完整后台任务指南(包括配置、subagents 和挂起/恢复)请参阅后台任务。

清理
清理的直接链接

每次 stream() 和 observe() 调用都会返回一个 cleanup 函数,用于拆除运行:取消 PubSub 订阅、从内部注册表移除运行,并删除该运行的缓存事件,使之后无人能够重放。

当你未自行调用 cleanup() 时,Mastra 会在运行完成、出错或被中止后的 cleanupTimeoutMs 调用它。默认值为 30 秒,因此已完成运行的重放仅限于该窗口,除非你配置不同值或更早调用 cleanup()。分离观察者或达到普通的 idleTimeoutMs 不会启动该计时器。设置 cleanupTimeoutMs: 0 可关闭计时器。

请从启动运行的那个进程调用 cleanup()。若要从 observe() 停止监视运行,请使用 detach() 或离开循环。

工具审批
工具审批的直接链接

持久化 agents 支持工具审批(human-in-the-loop)。当工具调用需要审批时,workflow 会挂起、发出 onSuspended 回调,并等待调用方通过 resume() 恢复:

src/mastra/run.ts
const { output, runId, cleanup } = await durableAgent.stream('Delete the old records', {
requireToolApproval: true,
onSuspended: ({ toolCallId, toolName, args }) => {
// Notify the user and ask for approval
},
})

审批后恢复挂起的运行:

await durableAgent.resume(runId, { approved: true })

崩溃恢复
崩溃恢复的直接链接

持久化 agents 可以在执行期间将每次运行的状态检查点写入存储。如果服务器进程在运行中途崩溃,该运行会在存储中保持 running 状态且不会自动重试;在下次服务器启动时,你可以重新驱动这些孤儿运行,使它们从上次中断处继续。对于滚动部署等有序关闭,生成的服务器还可以在退出前排空进行中的轮次。参见优雅关闭与滚动部署。

在默认持久化策略下,启用崩溃恢复时会写入这些 running 检查点。当 recovery.durableAgents: 'off'(默认值)时,持久化 agents 会为 pending、paused 和 suspended 运行持久化快照(human-in-the-loop 恢复所依赖的产物),并跳过每步的 running 写入,直到 mastra.shutdown() 开始。自定义 shouldPersistSnapshot 谓词会替换默认策略:包含 running 的谓词会在每一步写入这些检查点,不包含 running 的谓词则一个也不写,包括关闭期间。完整策略及覆盖方式请参阅快照持久化。

持久化 agent 运行不参与活跃 workflow 运行的通用启动时重启。持久化 agent 运行的唯一自动恢复路径是 recovery.durableAgents: 'auto',它会认领每个孤儿运行,并在重新驱动前注册其 thread 运行时。参见运行所有权。

注意

自动和手动恢复都会从最后一个持久化快照重新运行 agentic 循环,这可能重新发出 LLM 调用(产生真实成本)并重新执行工具调用。sub-agent 委托是一次生成的 agent-<name> 工具调用,恢复不会独立地对该委托内部的 LLM 或工具调用设置检查点。如果恢复重放了委托步骤,整个 sub-agent 运行会重新开始,并可能重复内部 LLM 调用和已完成工具副作用。请使工具(包括 sub-agents 使用的工具)具备幂等性,或对其外部副作用去重。

快照持久化
快照持久化的直接链接

createDurableAgent() 上的 shouldPersistSnapshot 选项(也被 agent 级 durable 配置接受)控制持久化 agent 写入哪些 workflow 快照。默认策略:

  • 始终持久化 pending、paused 和 suspended 快照。这些是 resume() 和工具审批所读取的快照,因此 human-in-the-loop 流程无需配置即可工作。
  • 当 recovery.durableAgents 为 'auto' 时,在每一步持久化 running 检查点。这些逐步骤写入的存在仅是为了让进行中的运行在崩溃后可恢复,因此关闭恢复时它们会被跳过,直到关闭阶段。
  • 即使关闭恢复,也会在 mastra.shutdown() 开始后运行所到达的每个步骤边界持久化 running 检查点。在排空窗口结束前到达步骤边界的运行,之后可通过 recover() 或 recoverActiveRuns() 恢复。在整个排空期间阻塞于单次 LLM 或工具调用的运行不会获得关闭检查点。

当 agent 配置了固定 memory 实例(memory: new Memory(...))时,running 检查点不会重复 memory 已存储的消息。从 memory 回忆的消息以及运行自身保存的消息(例如使用 savePerStep: true)会作为指向其 memory 行的小型引用存储,而不是完整内容,前提是它们仍与已存储行匹配(保存后被修改的消息保持内联)。这适用于检查点持有的对话的每一份副本,包括运行输入和步骤结果。因此长时间运行的检查点增长速度会慢得多。使用函数解析 memory 的 agents 会在每个检查点中保留完整记录,因为恢复的运行所解析到的 memory 可能不同。

若要在不启用自动恢复的情况下保留崩溃恢复检查点(例如在领导者选举后自行调用 recoverActiveRuns()),请传入包含 running 的谓词:

src/mastra/agents/durable.ts
export const durableResearcher = createDurableAgent({
agent,
shouldPersistSnapshot: ({ workflowStatus }) =>
['pending', 'paused', 'suspended', 'running'].includes(workflowStatus),
})

当自定义谓词排除 suspended 或 paused(会破坏 human-in-the-loop 恢复),或在 recovery.durableAgents 为 'auto' 时排除 running(会使 agent 对自动恢复不可见)时,Mastra 会记录一条警告。

Evented agents 始终持久化完整快照集:evented 引擎通过存储协调 worker,因此 running 行是其执行模型的一部分。Inngest agents 始终只持久化 suspended 快照,因为 Inngest 自身的重放提供持久性。两者都接受 shouldPersistSnapshot 以保持 API 对称,但会记录警告并忽略它。

自动恢复
自动恢复的直接链接

在 Mastra 配置中将 recovery.durableAgents 设置为 'auto'。deployer 会在启动时调用 recoverAllDurableAgents(),与 workflow 运行重启同时进行(两者并发运行):

src/mastra/index.ts
export const mastra = new Mastra({
agents: { myAgent: durableAgent },
storage: new PostgresStore({ connectionString: process.env.DATABASE_URL! }),
recovery: { durableAgents: 'auto' },
})

启动时,它会发现每个已注册、且运行卡在 running 状态的持久化 agent,并从最后一个持久化快照重新驱动它们。

恢复会串行尝试运行,每次运行最多等待 30 秒,用于 recover() 设置和整个已恢复 workflow 的完成。如果该等待超时,尝试会在后台继续,而恢复会转向后续运行和 agents。发现过程和被覆盖的自定义恢复方法不受此预算限制。

关闭开始时,恢复会停止派发新的运行和 agents,并取消待处理的重新检查。原始尝试(包括等待超时的尝试)仍会被 Mastra 的共享关闭排空跟踪。恢复超时不会取消执行,也不会增加单独的排空窗口。

恢复不会接管另一个执行仍在驱动的运行。它会跳过该运行,并在该执行的认领可能已失效后再检查一次。在重启前不久进程崩溃的运行仍会被恢复,无需额外调用。

手动恢复
手动恢复的直接链接

如果你需要更精细的控制(例如按计划运行恢复),请直接调用这些方法:

// Recover all durable agents
const result = await mastra.recoverAllDurableAgents()
console.log(
`Recovered ${result.recovered} runs (${result.succeeded} ok, ${result.failed} failed, ${result.skipped} skipped)`,
)

// Recover a specific agent
const { recovered } = await durableAgent.recoverActiveRuns()
for (const run of recovered) {
if (run.status === 'skipped') console.log(`${run.runId} was skipped: ${run.reason}`)
}

// Recover a single known run
await durableAgent.recoverActiveRuns({ runId: 'run-abc-123' })

recoverAllDurableAgents() 返回计数,并自行安排符合条件的重新检查所有权。recoverActiveRuns() 以 success、failed 或 skipped 返回每次运行的结果,且不会重新检查被跳过的运行。因另一个进程驱动而被跳过的运行会携带 retryAt,即其认领失效(除非续期)的时间。超时的尝试则返回 status: 'skipped'、reason: 'recovery-timeout' 且没有 retryAt,因此 Mastra 不会自动重试它。只有 skipped 计数包含该尝试;即使它后来完成,recovered、succeeded 和 failed 计数也不包含它。

手动恢复读取与自动恢复相同的 running 检查点。对于使用默认快照策略且 recovery.durableAgents 为 'off' 的 DurableAgent,进行中的运行仅会在 mastra.shutdown() 开始后到达的步骤边界处设置检查点。在此之前崩溃,或在排空期间未到达步骤边界的运行没有检查点,因此 listActiveRuns() 和 recoverActiveRuns() 找不到它。参见快照持久化。

若要接管仍在实时运行的运行(例如被挂起执行持有的运行),请使用 force: true 调用 recover():

const { output } = await durableAgent.recover('run-abc-123', { force: true })

持有该运行的执行会失去其认领。当该执行检测到丢失时,Mastra 会请求取消。忽略取消的工作可能继续运行。对于基于存储的认领,流会丢弃来自较旧认领世代的事件。取消限制请参阅所有权丢失后停止工作。不使用 force 时,对于实时运行,recover() 会抛出 DURABLE_AGENT_RUN_ACTIVE。即使使用 force,recover() 也会拒绝由同一进程正在执行的运行。

运行所有权
运行所有权的直接链接

每次 stream()、generate()、resume() 和 recover() 调用都会在执行前认领运行,并每 5 秒续期一次。认领在上次续期后 15 秒失效,因此进程崩溃的运行会在 15 秒内变为可恢复。在此之前,恢复会将该运行视为实时,针对该运行的 stream() 或 resume() 调用最多等待 5 秒以获取认领,然后抛出 DURABLE_AGENT_EXECUTION_CONFLICT。mastra.shutdown() 会停止排空窗口后仍在执行的运行,不再写入,并释放其认领。下次启动时即可恢复它们,而无需等待认领失效。设置 MASTRA_AGENT_THREAD_LEASE_TTL_MS 可更改失效时间。续期每三分之一时间进行一次,除非 MASTRA_AGENT_THREAD_LEASE_RENEW_INTERVAL_MS 设置了短于 TTL 的间隔。

认领的强制执行依赖于 workflows store。当 store 支持运行隔离(run fencing)时,认领是 store 中的一条记录,每次写入都会在同一操作中对照该认领进行检查。一旦另一个执行认领了该运行,来自失去认领的执行写入会被拒绝。该执行的消息、thread 和工作记忆写入只有在 memory store 也支持运行隔离时才会被拒绝,因此当 agent 的 Memory 使用不支持该功能的存储适配器时,它们仍会写入。以下存储适配器支持运行隔离:

  • @mastra/core/storage 中的 InMemoryStore
  • @mastra/pg
  • @mastra/libsql 和 @mastra/turso
  • @mastra/mysql
  • @mastra/mssql
  • @mastra/oracledb
  • @mastra/spanner
  • @mastra/dsql
  • @mastra/cloudflare-d1
  • @mastra/cloudflare,配合 CloudflareDOStorage
  • @mastra/convex
  • @mastra/mongodb(在副本集或分片集群上)
  • @mastra/dynamodb
  • @mastra/redis
  • @mastra/upstash
  • @mastra/valkey

在 Convex 上,运行隔离在你部署的 Mastra 服务器函数中运行。升级 @mastra/convex 后请重新部署 Convex 函数。在重新部署之前,持久化 agent 运行会失败并提示需要重新部署,而其他写入仍可正常工作。

支持运行隔离的 stores 会为每次运行保留一条认领记录,并为带 memory 的运行额外保留一条 memory fence 记录。支持保留策略的 stores 会通过 workflows.runOwnership 和 memory.runFences 保留键修剪它们。Redis、Upstash 和 Valkey 则会自行使其过期:认领在其上次认领、续期或释放后 7 天过期,fence 在退役后 7 天过期。运行的第一个世代来自 store 的时钟,因此在记录被修剪后复用 runId 的运行,其世代仍会高于其先前执行的 fences 和流事件。

对于任何其他 workflows store,认领是 PubSub 后端上的租约。该租约可防止两个执行同时认领运行,但来自失去运行的执行写入不会被拒绝。在先前执行仍实时运行时被接管的运行,最终可能包含该执行的输出。当执行失去租约且没有其他执行接管该运行时,该运行会继续被持有最多 15 秒。在此之前,不带 force 的 recover() 会抛出 DURABLE_AGENT_RUN_ACTIVE,并将 retryAt 设置为持有确定结束的时间。当 Mastra 针对不支持运行隔离的 workflows 或 memory store 恢复运行时,会记录一条警告。

租约仅协调共享它的进程。默认的 EventEmitterPubSub 覆盖单个进程。UnixSocketPubSub 覆盖一台主机上的进程。RedisStreamsPubSub 和 ValkeyStreamsPubSub 覆盖连接到同一服务器的每个实例。GoogleCloudPubSub 不提供租约,因此对于缺少运行隔离的 store,每次认领都会成功,恢复可能接管仍在实时运行的运行。

所有权丢失后停止工作
所有权丢失后停止工作的直接链接

当持久化和 evented agents 的步骤检测到其不再拥有运行时,它们会请求取消进行中的工具和模型调用。另一个进程中的 evented workers 会在认领续期间隔检查所有权,但不续期原始执行的认领。默认每 5 秒一次,即 MASTRA_AGENT_THREAD_LEASE_TTL_MS 的三分之一。检测取决于后端响应时间。如果所有权检查持续失败或停止响应,步骤会在一个租约 TTL(默认 15 秒)后不再信任其认领。

取消是协作式的。对于可取消的操作,请使用工具执行上下文的 abortSignal,并在开始另一个副作用之前检查它。忽略该 signal 的工具可能继续运行。已在 Mastra 之外完成的工作不会回滚。

恢复可能在旧调用检测到所有权丢失之前启动相同的工具调用。即使工具处理取消,也要使其幂等或对外部效果去重。取消减少了重叠工作,但不保证恰好一次执行。

多实例部署
多实例部署的直接链接

每个副本都可以以 recovery.durableAgents: 'auto' 启动。同时启动的副本会竞相恢复相同的孤儿运行,但每次运行只有一个认领成功,其他副本会跳过它。这需要每个副本共享的认领:支持运行隔离的 workflows store,或每个副本共享租约的 PubSub 后端。若两者都不具备,请将恢复置于你自己的领导者选举之后,或从单个副本运行。

相关内容
相关内容的直接链接