LLM WikiAccess-protected knowledge portal

WIKI

Mastra 1.51: Durable Agent Crash Recovery로 끊긴 RUNNING 실행을 다시 붙이는 법

왜 지금 봐야 하나 2026년 7월 15일 공개된 Mastra 1.51.0의 핵심은 모델 추가나 UI 정리가 아니다. 이미 돌고 있던 durable agent가 프로세스 재시작 중에 끊겼을 때, 그 RUNNING 실행을 다시 찾아 붙일 수 있게 됐다는 점 이다. 이전에도 Mastra의 durable agent는 강했다. 클라이언트가 스트리밍 중간에 끊겨도 observe 로 다시 붙을 수 있었고, tool approval처럼 사

경로human/study/content/ai-frontier/44-mastra-1-51-durable-agent-crash-recovery.md
카테고리Study
태그#agent #ai-review #crash #durable #mastra #portfolio #recovery #study

왜 지금 봐야 하나

2026년 7월 15일 공개된 Mastra 1.51.0의 핵심은 모델 추가나 UI 정리가 아니다. 이미 돌고 있던 durable agent가 프로세스 재시작 중에 끊겼을 때, 그 RUNNING 실행을 다시 찾아 붙일 수 있게 됐다는 점이다.

이전에도 Mastra의 durable agent는 강했다. 클라이언트가 스트리밍 중간에 끊겨도 observe()로 다시 붙을 수 있었고, tool approval처럼 사람이 끼어드는 지점에서는 resume()으로 이어갈 수 있었다. 하지만 서버 프로세스 자체가 내려가면 얘기가 달랐다. PubSub 스트림과 캐시가 남아 있어도, 실제 agentic loop를 이어 가려면 메모리 안에 있던 런타임 상태를 다시 만들어야 했기 때문이다.

Mastra 1.51은 이 빈칸을 메운다.

  1. DurableAgent.listActiveRuns()저장소에 남은 RUNNING 스냅샷을 찾을 수 있다.
  2. recover(runId)단일 실행을 다시 붙여 스트리밍을 이어갈 수 있다.
  3. recoverActiveRuns()Mastra.recoverAllDurableAgents()서버 부팅 시점 또는 운영자 개입으로 여러 실행을 다시 돌릴 수 있다.
  4. POST /agents/:agentId/recoverclient-jsagent.recover({ runId })대시보드나 운영 도구에서도 같은 흐름을 사용할 수 있다.

즉, 1.51의 durable agent는 "연결이 끊겨도 다시 보는 스트림" 수준에서 한 단계 올라가, 배포·크래시 이후에도 다시 붙일 수 있는 실행 단위가 됐다.


핵심 변화 한눈에 보기

상황1.50까지 주된 선택지1.51에서 추가된 선택지운영상 의미
네트워크 끊김, 서버는 살아 있음observe(runId, { offset })동일캐시된 이벤트를 replay하고 live stream에 다시 붙음
tool approval / suspend 이후 재개resume(runId, resumeData)동일사람이 승인한 뒤 같은 실행을 이어 감
서버 재시작 중 RUNNING 실행 끊김사실상 표준 경로 없음listActiveRuns() + recover(runId)메모리 밖에 남은 snapshot으로 loop를 다시 붙임
여러 orphaned run을 한 번에 복구수동 운영recoverActiveRuns() / Mastra.recoverAllDurableAgents()배포 후 운영 훅이나 부팅 루틴에서 일괄 처리 가능
대시보드·운영 툴에서 복구서버 내부 코드 필요POST /agents/:agentId/recover / agent.recover({ runId })브라우저/운영 UI에서도 복구 스트림을 붙일 수 있음
자동 부팅 복구없음recovery: { durableAgents: 'auto' }단, 비용·tool 재실행·멀티 인스턴스 경합을 감수해야 함

observe()만으로는 부족했던 이유

Mastra 문서는 durable agent를 "disconnect 이후에도 다시 붙을 수 있는 스트림"으로 설명한다. 이 설명은 맞지만, 전제가 하나 있다. 프로세스가 살아 있어야 한다.

observe()는 PubSub와 캐시에 쌓인 이벤트를 다시 읽어 오는 경로다. 네트워크가 잠깐 끊겼거나 브라우저 탭을 새로 열었을 때는 충분하다. 하지만 서버가 재시작되면 다음 두 가지가 동시에 사라질 수 있다.

그래서 1.51 이전에는 "이 run이 storage에 RUNNING으로 남아 있다"는 사실만으로는 충분하지 않았다. 이벤트를 다시 읽는 것과 실행 자체를 다시 움직이는 것은 다른 문제이기 때문이다.

Mastra 1.51이 새로 추가한 것은 정확히 이 두 번째 문제에 대한 표준 해법이다. recover()는 단순 replay API가 아니라, 저장된 workflow snapshot에서 실행 상태를 다시 만들어 background에서 loop를 재구동하는 경로다.

Mastra 1.51은 "끊긴 스트림"이 아니라 "고아가 된 RUNNING 실행"을 다시 붙인다 1) 실행 중에는 durable workflow snapshot + PubSub/cache가 함께 쌓인다 Client `stream()` 호출 DurableAgent loop tool call · background task · memory flush Workflow snapshot status=`running` agentId · threadId · resourceId PubSub + cache chunk stream late subscriber replay deploy / crash / process restart 2) 1.51에서는 storage에서 RUNNING snapshot을 찾고, 실행을 다시 재구동한다 `listActiveRuns()` agentId 기준으로 RUNNING run 발견 thread/resource/date filter 가능 `recover(runId)` message list · model · tools · memory request context · saveQueueManager 재구성 pubsub topic 재구독 후 workflow restart HTTP / Client surface `POST /agents/:agentId/recover` `agent.recover({ runId })` 새 스트림 남은 출력 replay + live continuation 핵심 경계 `observe()`는 연결 복구, `recover()`는 프로세스 재시작 이후 실행 복구다. 둘을 같은 문제로 보면 운영 설계가 어긋난다.
Mastra 1.51 durable crash recovery 경로

1. listActiveRuns()는 어떤 실행을 복구 대상으로 보나

이번 릴리스에서 가장 먼저 눈에 들어오는 메서드는 DurableAgent.listActiveRuns()다. 이름만 보면 단순 조회 API 같지만, 실제 의미는 더 구체적이다.

이 설계는 중요하다. 복구 대상은 "예전에 한 번 돌았던 run 전체"가 아니라, 프로세스 재시작 직전에 실제로 loop가 살아 있던 실행으로 좁혀진다. suspended run은 복구 대상이 아니다. 그것들은 resume()으로 이어야 하고, listSuspendedRuns()가 따로 있다.

const durable = mastra.getAgent('researcher');

const { runs, total } = await durable.listActiveRuns({
  resourceId: 'repo-123',
  fromDate: new Date('2026-07-15T00:00:00Z'),
});

for (const run of runs) {
  console.log(run.runId, run.status, run.threadId, run.updatedAt);
}

운영 관점에서 보면 listActiveRuns()는 세 가지 상황에서 바로 쓸 수 있다.

  1. 배포 직후 orphaned run이 남았는지 확인하는 대시보드 조회 API
  2. 특정 고객 resourceId에 묶인 실행만 복구하는 부분 복구 도구
  3. 부팅 훅 전에 어떤 run이 실제 대상이 될지 검증하는 dry-run 성격의 점검 단계

2. recover(runId)는 무엇을 다시 만들고, 왜 observe()와 다른가

릴리스 노트와 소스 주석을 같이 읽으면 recover(runId)의 역할이 분명해진다. 이 메서드는 단순히 PubSub를 다시 여는 게 아니다. 저장된 workflow snapshot에서 실행의 비직렬화 상태를 다시 조립한다.

Mastra 코어의 주석이 명시적으로 나열하는 재구성 대상은 다음과 같다.

이걸 다시 올린 뒤 PubSub 토픽에 재구독하고, workflow를 background에서 다시 움직인다. 그래서 recover()는 반환값도 DurableAgentStreamResult다. 즉 호출자는 새로운 live stream 에 붙으면서, 남은 출력을 계속 받아볼 수 있다.

const { output, fullStream, cleanup } = await durable.recover(runId, {
  onChunk: chunk => process.stdout.write(chunk.payload?.text ?? ''),
});

for await (const event of fullStream) {
  // replay + live continuation
}

cleanup();

observe() / resume() / recover()를 헷갈리면 안 되는 이유

메서드쓰는 순간전제실패하는 대표 상황
observe(runId, { offset })스트리밍 중 연결만 끊겼을 때프로세스 쪽 실행 상태가 아직 살아 있음프로세스 재시작으로 run registry가 사라진 경우
resume(runId, resumeData)suspend된 run을 사람이 승인하거나 외부 데이터를 넣어 이어갈 때run이 suspended 상태로 저장돼 있음RUNNING 중 crash가 났을 때
recover(runId)RUNNING 상태에서 프로세스가 내려간 뒤 다시 붙을 때storage에 RUNNING snapshot이 남아 있음tool이 비멱등이고 재실행을 허용하지 않는 경우

이 표의 의미는 단순 분류가 아니다. 운영 절차 자체가 달라진다.

같은 runId를 다루더라도, 어떤 문제가 발생했는지에 따라 호출 경로가 달라진다.


3. 단일 실행이 아니라 서버 전체를 복구하려면

Mastra 1.51은 단일 run만 다루는 데서 멈추지 않는다. 부팅 시점 복구까지 표면화했다.

핵심 API는 두 개다.

첫 번째는 agent 단위다. 두 번째는 Mastra 인스턴스에 등록된 durable agent 전체를 순회하면서 recoverActiveRuns()를 호출한다. 반환도 운영자가 바로 보기 좋은 집계형이다.

const result = await mastra.recoverAllDurableAgents();
// { agents, recovered, succeeded, failed }

그리고 이 경로는 설정으로도 연결된다.

import { Agent } from '@mastra/core/agent';
import { Mastra } from '@mastra/core';

const researcher = new Agent({
  id: 'researcher',
  name: 'Researcher',
  model: 'openai:gpt-5.6',
  instructions: 'Investigate and summarize.',
  durable: true,
});

export const mastra = new Mastra({
  agents: { researcher },
  recovery: { durableAgents: 'auto' },
});

여기서 중요한 건 durable: truerecovery: { durableAgents: 'auto' }가 다른 층위의 설정이라는 점이다.

즉, durable agent를 쓰고 있다고 해서 crash recovery가 자동으로 켜지는 건 아니다. 자동 복구는 명시적으로 opt-in 해야 한다.


4. 이 기능이 강력하지만 조심해야 하는 이유

Mastra는 auto recovery를 기본값으로 켜지 않았다. 그 이유가 문서와 소스에 분명히 적혀 있다.

4-1. 복구는 "다시 붙는 것"이면서 동시에 "다시 실행하는 것"이다

소스 주석은 auto recovery가 last persisted snapshot에서 agentic loop를 다시 시작한다고 못 박는다. 이 말은 곧 두 가지 비용이 다시 발생한다는 뜻이다.

그래서 recovery는 언제나 idempotent tool 설계와 같이 읽어야 한다. 예를 들면 다음과 같다.

4-2. 멀티 인스턴스에서는 아직 lease/lock이 없다

Mastra 코어는 이 점도 숨기지 않는다. 여러 인스턴스가 동시에 떠 있는 배포에서는 여러 replica가 같은 orphaned run을 동시에 recover하려고 경쟁할 수 있다. 아직 lease/lock 메커니즘이 없기 때문이다.

따라서 운영 기준은 명확하다.

4-3. 캐시가 in-memory면 "재연결"은 단일 프로세스 범위를 벗어나지 못한다

Durable agent 문서는 기본 캐시가 in-memory라고 설명한다. 이 설정은 개발에는 편하지만, production에서는 한계가 분명하다.

즉, 1.51이 crash recovery를 열어 주긴 했지만, 운영 품질은 cache/pubsub 백엔드를 무엇으로 두느냐에 따라 달라진다.

4-4. cleanup()는 너무 빨리 부르면 상태를 스스로 지워 버린다

DurableAgent reference는 observe()가 돌려주는 cleanup()이 registry entry와 cached event를 파괴한다고 경고한다. 특히 run이 suspended 상태에서 나중에 다시 이어야 한다면, 너무 일찍 cleanup()을 부르면 복구 경로를 스스로 지워 버릴 수 있다.

이 경고는 recovery에서도 그대로 중요하다.


5. 대시보드와 운영 툴에서도 같은 흐름을 쓸 수 있다

이번 릴리스에서 실무적인 부분은 HTTP + client surface다. 이전에는 recovery가 서버 내부 API에 가까웠지만, 1.51부터는 표준 route가 생겼다.

서버 핸들러는 이 route를 "orphaned RUNNING durable-agent run after a process restart" 용도로 정의하고, durable agent가 아닌 경우는 거절한다. 또한 기존 agents API와 같은 권한/ownership 규칙을 적용한다.

const stream = await mastraClient.getAgent('support').recover({
  runId: 'run-abc123',
});

await stream.processDataStream({
  onChunk: chunk => {
    console.log(chunk);
  },
});

이 표면이 생기면서 가능한 운영 패턴이 달라진다.

  1. 배포 후 관리자 화면에서 listActiveRuns() 결과를 보여 준다.
  2. 운영자가 특정 run을 선택한다.
  3. 브라우저나 내부 admin tool이 agent.recover({ runId })를 호출한다.
  4. 남은 출력을 화면에서 그대로 본다.

이제 recovery가 프레임워크 내부의 숨겨진 기능이 아니라, 운영 워크플로에 붙일 수 있는 제어면이 된 셈이다.


6. 언제 도입할 만한가

이 변화는 모든 Mastra 사용자에게 같은 무게로 다가오지 않는다. 특히 아래 세 부류에서 체감이 크다.

1) 장기 실행 조사 에이전트

수 분~수십 분 동안 검색, 정리, 도구 호출을 반복하는 run은 deploy 타이밍과 충돌하기 쉽다. 이전에는 "다시 보내라"에 가까웠다면, 1.51 이후에는 살아 있던 RUNNING 실행을 다시 붙여 이어갈 수 있다.

2) 사람 승인(tool approval)과 background task를 섞는 에이전트

이 유형은 원래도 resume()untilIdle을 많이 쓴다. 여기에 crash recovery가 더해지면, 네트워크 끊김·사람 승인·프로세스 재시작을 각각 다른 복구 경로로 분리해서 운영할 수 있다.

3) 운영 UI나 내부 대시보드를 직접 만드는 팀

HTTP recover route와 client SDK surface 덕분에, recovery가 더 이상 서버 안쪽의 전용 스크립트가 아니다. 운영 도구에 바로 붙일 수 있는 기능이 됐다.

반대로, 다음 조건이라면 아직 보수적으로 보는 편이 낫다.


도입 전 체크리스트

1) 실패 유형을 먼저 분리한다

2) tool의 멱등성을 점검한다

3) storage / cache / pubsub 구성을 따로 본다

4) auto recovery를 켤 환경인지 판단한다

5) 운영 UI는 조회와 복구를 분리한다


한 줄 결론

Mastra 1.51의 durable crash recovery는 "스트림을 다시 보는 기능"이 아니라, 프로세스 재시작 이후에도 RUNNING agentic loop를 다시 살릴 수 있게 만든 운영 기능이다. 다만 그것은 공짜 복원이 아니라, snapshot 이후 LLM 호출과 tool 실행을 다시 감수하는 복구다. 그래서 이 릴리스의 진짜 가치는 API 추가보다도, 어떤 tool은 다시 실행해도 안전한가를 팀이 처음으로 명시하게 만든다는 데 있다.

References