Pausing an agent mid-task and resuming it four minutes later, with its memory intact
에이전트를 작업 중 멈췄다가 4분 뒤 메모리 그대로 재개했습니다
DigitalOcean Managed Agents의 일시 중지가 프로세스와 메모리까지 보존하는지 직접 시험했습니다. 셸 변수 카운터와 에이전트 대화 기록이 재개 후에도 유지됐고, 실행 중인 세션을 포크하면 동일한 시점의 프로세스가 여러 샌드박스에서 따로 진행됐습니다.
- 주제
AI 요약
에이전트 실행 환경에서 컨테이너 격리는 이미 흔한 기능입니다. 이 글은 DigitalOcean Managed Agents의 일시 중지가 파일뿐 아니라 실행 중인 프로세스와 메모리까지 보존한다는 설명을 직접 검증합니다. 파일을 썼다가 다시 읽는 시험은 디스크 보존만 확인하므로, 프로세스 메모리에만 존재하는 셸 변수 카운터를 초마다 증가시키고 로그에는 값과 시각만 추가하도록 만들었습니다.
멈춘 시간만큼 카운터도 멈췄습니다
샌드박스의 exec 채널이 닫힐 때 자식 프로세스도 종료되는 문제를 피하려고 setsid nohup ... & disown으로 스크립트를 실행했습니다. 약 1분 뒤 세션을 일시 중지하고 커피를 마신 다음 재개하자 로그에는 47 08:05:42 다음으로 48 08:10:10이 기록됐습니다. 파일을 복원해 새 프로세스를 띄웠다면 셸 변수는 초기화돼 카운터가 1부터 다시 시작했을 테니, 연속된 47과 48은 같은 프로세스가 상태를 유지했다는 증거입니다. 두 기록 사이에는 4분 28초가 비었습니다.
일시 중지 요청은 0.86초, 재개 요청은 1.16초 만에 끝났습니다. 글은 이 숫자보다 중지된 동안 세션이 자원을 소비하지 않았다는 점에 주목합니다. 에이전트의 대화 맥락도 따로 확인했습니다. 중지 전에 HARBOUR-7742라는 무작위 티켓 식별자를 만들게 한 뒤, 재개 후 파일을 읽지 않고 대화 기록만으로 이름을 물었습니다. 에이전트는 8개 출력 토큰으로 답했습니다. 운영체제 프로세스 상태와 에이전트 맥락이 모두 돌아왔습니다.
마이크로VM에서 실행하고, 상태를 포크했습니다
실행 환경은 KVM 하이퍼바이저를 쓰는 마이크로VM이었습니다. VM마다 2 vCPU와 약 3,939MB 메모리, 자체 블록 장치와 커널이 있었고 커널 버전은 6.1.176이었습니다. 세션 생성부터 READY 상태까지는 15.97초가 걸렸습니다. 제공 크기는 1 vCPU·1GB부터 16 vCPU·32GB까지입니다. 에이전트는 DigitalOcean 추론 엔드포인트의 DeepSeek v4 Pro를 사용했습니다. 단일 요청은 입력 15,793토큰, 출력 91토큰이었고 7.3초가 걸렸습니다.
실행 중인 부모 세션을 두 번 포크한 뒤 세 환경의 카운터를 비교하자 부모와 두 자식 모두 PID 590을 유지했습니다. 잠시 뒤 카운터는 각각 177, 165, 162였고, 1분 후에는 244, 231, 228이 됐습니다. 세 환경은 포크 시점의 실행 상태를 복제한 뒤 각자 진행했습니다. 비싼 설정 작업을 되풀이하지 않고 같은 상태에서 여러 선택지를 시험하는 기반이 됩니다. 두 세션을 포크하는 데 30.98초, 체크포인트 생성에는 25.25초가 걸렸습니다. 체크포인트 크기 약 111GB는 실제 저장량이 아니라 희소 할당 크기라고 설명합니다.
네트워크 기본값과 자격 증명에 주의해야 합니다
새 샌드박스는 별도 설정 없이 example.com과 api.github.com에 접속했습니다. 매니페스트에 api.github.com만 허용 목록으로 추가하자 해당 호스트는 HTTP 200을 반환했고 다른 접속은 차단됐습니다. 따라서 기본 세션은 셸과 일반 인터넷 접속을 허용하는 상태입니다. HARNESS_INFERENCE_API_KEY도 샌드박스 내부에서 일반 환경 변수로 읽을 수 있어, 실행 중인 프로세스가 값을 출력할 수 있습니다. 글은 이런 조건에서 송신 허용 목록이 특히 중요하다고 지적합니다.
서비스는 단일 리전의 공개 프리뷰이며 SLA는 없습니다. 세션 생성에는 시간이 들지만 중지와 재개는 빠릅니다. 작성자가 네 세션과 두 포크, 체크포인트 하나, 여러 exec 호출과 추론 요청을 실행한 비용은 약 7센트였습니다. 체크포인트 플래그를 --name으로 잘못 가정했다가 실제 옵션이 --label이라는 오류 메시지를 확인한 사례도 소개합니다. CLI 인자나 백그라운드 프로세스 동작을 추측하지 말고 오류 출력을 확인하라는 경험입니다.
dev.to 반응
- @_firelinks — 일시 중지와 포크가 프로세스에 보이지 않는다는 점이 유용하면서도, 프로세스가 시계나 식별자에 연결된 값을 들고 있으면 문제가 됩니다. 카운터가 보여주듯 VM 안에서는 4분 반이 흐른 사실을 알지 못합니다. 일시 중지의 위험은 임대(lease)입니다. 에이전트가 60초짜리 잠금이나 만료가 짧은 토큰을 얻고 사람의 검토를 기다리다 재개되면, 여전히 둘 다 유효하다고 행동할 수 있습니다. 그사이 잠금은 만료됐고 다른 작업자가 가져갔을 수 있습니다. 긴 GC 중단과 같은 문제이며, 해결책도 같습니다. 클라이언트가 TTL을 믿게 두지 말고 리소스가 확인하는 펜싱 토큰을 써야 합니다. 포크의 위험은 식별자입니다.
HARBOUR-7742는 이제 세 샌드박스에 모두 존재합니다. 포크 전에 에이전트가 만든 멱등성 키, 요청 ID, nonce도 자식마다 동일하며 각 자식은 그 값을 자신의 것처럼 제시합니다. 두 자식이 같은 결제 API나 티켓 API를 호출하면 제공자는 하나의 키에 서로 다른 두 요청 본문을 받습니다. 포크 전에 60초 Redis 잠금을 얻고 재개 후 그 잠금으로 쓰기를 시도하거나, 포크 전에 만든 UUID를 세 자식에서 출력하면 이 두 문제를 확인할 수 있습니다. - @mrsaynothing — 셸 변수 카운터는 이런 주장을 시험하는 데 적절한 방법입니다. 한 줄에 숫자 하나라서 중간에 벤더 대시보드가 끼지 않습니다. 4분 28초 동안 47에서 48로 바뀐 결과는 마케팅 문구와 상관없이 프로세스가 계속 실행된 게 아니라 멈춰 있었다는 뜻입니다. 포크에서는 카운터가 복제됐나요, 아니면 둘로 나뉘었나요?
- @max_quimby — 파일시스템 복원만으로 시험을 통과할 수 없게 설계한 점이 좋습니다. 쓰기 전용 로그에 셸 변수 카운터를 기록하는 방식은 볼륨 복원이 아니라 실제 메모리 상태를 증명하는 가장 깔끔한 시험입니다.
setsid nohup ... & disown방식도 익숙합니다. exec 채널이 자식 프로세스를 정리하는 동작은 많은 샌드박스에서 백그라운드 작업을 조용히 종료시키고, 사람들은 플랫폼 탓을 합니다. 궁금한 점은 외부 상태입니다. 열린 TCP 연결이나 DB 소켓, 진행 중인 HTTP 요청은 중지 동안 어떻게 됐나요? CRIU 방식 체크포인트로 프로세스를 복원해도 네 분 뒤에는 상대편 상태가 달라졌을 테니까요. 포크에서 PID나 파일 디스크립터가 복제된 점이 ‘이상한’ 동작과 관련 있었나요? 스냅샷·재개 시스템은 이런 부분에서 흥미로운 문제와 실제 에이전트 작업의 함정을 드러냅니다.
원문: dev.to / 번역·요약: Trawling