Skip to main content
이 가이드에서는 샌드박스가 생성부터 종료까지 진행되는 과정과 각 단계의 상태, 시작 및 대기 방법, 정상적으로 중지하는 방법을 설명합니다. 생성 패턴을 선택하거나, 시작 시점을 제어하거나, SDK 코드에서 종료를 안정적으로 처리해야 할 때 이 가이드를 참고하세요.

인증 선택

섹션에서 CKS를 별도로 지정하지 않는 한, 이 예시는 서버리스 용량에서 실행됩니다. 샌드박스를 소유한 계정의 사용자 인증 정보를 선택하세요. 키 또는 토큰을 획득하는 방법은 사용자 인증 정보 선택 및 조회를 참조하세요. 설치 명령어는 활성화된 Python 가상 환경에서 실행하세요. 사용 중인 사용자 인증 정보 탭의 Python 코드를 sandbox_auth.py로 저장하고, 이 페이지에서 실행할 Python script와 같은 디렉터리에 두세요. 이 파일에는 사용자 인증 정보 자체가 아니라 어떤 인증 방식을 사용할지만 저장됩니다. 예시에서는 이 파일에서 AUTH를 임포트한 후, 새 샌드박스나 세션을 만들 때마다 명시적으로 전달합니다.
SDK의 W&B 인증 전략으로 Forge API 키를 사용하세요.
sandbox_auth.py
CKS 배치를 사용하려면 CoreWeave 토큰을 선택하고 러너를 활성화한 다음, 샌드박스를 생성할 때 또는 SandboxDefaults에서 placement_mode="cks"를 설정하세요. auth=AUTH로 세션을 생성하면 해당 세션이 소유한 샌드박스도 함께 인증됩니다. 샌드박스에 다시 연결하거나, 목록을 조회하거나, 정리할 때도 동일한 사용자 인증 정보를 사용하세요.

라이프사이클 상태

모든 샌드박스는 시작, 실행, 종료 과정에서 일련의 상태를 거칩니다. SDK는 이러한 상태를 SandboxStatus 값으로 나타냅니다. PENDING과 CREATING은 일시적인 상태입니다. SDK는 이 상태를 자동으로 계속 폴링합니다. TERMINATING은 일시적인 백엔드 상태로, wait_until_complete()와 stop().result()는 이 상태를 거쳐 종료 상태에 도달하도록 합니다. RUNNING은 안정적인 동작 상태입니다. COMPLETED와 FAILED는 종료 상태입니다. SDK는 폴링 시 UNSPECIFIED를 COMPLETED로 매핑합니다. 샌드박스가 생성, 완료 또는 실패할 때 워크플로를 시작할 수 있습니다. 샌드박스의 Weights & Biases 프로젝트에서 샌드박스 상태 변경 자동화를 생성하세요. 예를 들어 Slack channel에 메시지를 게시하거나 웹훅을 호출할 수 있습니다.

생성 패턴

샌드박스는 두 가지 방식으로 생성할 수 있으며, 시작 RPC가 호출되는 시점이 다릅니다. 다음 섹션에서는 각 패턴과 선택 기준을 설명합니다.

Sandbox.run(): 즉시 시작

Sandbox.run()은 샌드박스를 생성하고 내부적으로 start().result()를 호출하며, 백엔드가 요청을 수락할 때까지 대기합니다:
첫 번째 위치 인수는 명령어이고, 나머지는 해당 명령어의 인수입니다:
Sandbox.run()은 명령어와 그 인수를 가변 위치 문자열로 받습니다. command나 args는 키워드 인수로 전달할 수 없습니다.

session.sandbox(): 지연 시작

session.sandbox()는 네트워크 호출 없이 샌드박스 객체를 생성합니다. 시작 RPC는 처음 사용할 때 실행됩니다:

메인 명령 수명

run() 또는 session.sandbox()에 전달된 메인 명령은 샌드박스의 메인 프로세스입니다. 메인 프로세스가 종료되면 어떻게 처리되는지는 종료 상태에 따라 달라집니다.
  • 종료 상태 0: 샌드박스가 COMPLETED 상태로 전환됩니다.
  • 0이 아닌 종료 상태: 플랫폼이 메인 프로세스의 컨테이너를 재시작합니다. 이미 RUNNING에 도달한 샌드박스는 재시작되는 동안에도 RUNNING 상태를 유지하고, 아직 도달하지 않은 샌드박스는 CREATING 상태를 유지합니다. wait_until_complete()는 재시작되는 동안에도 timeout에 도달할 때까지 계속 대기합니다.
  • 재시작 한도 도달: 메인 프로세스가 0이 아닌 상태로 계속 종료되면, 재시작 한도(현재 6회)에 도달했을 때 샌드박스가 FAILED 상태로 전환됩니다.
메인 프로세스가 성공적으로 종료되면 샌드박스도 종료됩니다.
짧은 명령을 실행하고 그 출력을 캡처해야 하는 경우, 장시간 실행되는 샌드박스에서 exec()을 사용하세요. 짧은 명령을 메인 프로세스로 만들지 마세요.

샌드박스 시작

샌드박스 객체가 존재한 후에는 명시적으로 시작하거나 SDK가 처음 사용할 때 시작하도록 할 수 있습니다. 다음 섹션에서는 두 가지 접근 방식과 컨텍스트 매니저가 어떻게 상호작용하는지 설명합니다.

명시적 시작

start()는 시작 RPC를 전송하고 OperationRef[None]을 반환합니다:
이 기능은 타이밍을 제어하거나 시작 오류를 오퍼레이션 오류와 별도로 처리하려는 경우에 유용합니다.

자동 시작

대부분의 오퍼레이션은 샌드박스가 아직 시작되지 않았다면 자동으로 시작합니다. 일반적으로는 샌드박스를 생성한 후 바로 사용하면 됩니다.

컨텍스트 관리자와 start

컨텍스트 관리자(with/async with)는 진입 시 start()를 호출하지만 wait()는 호출하지 않습니다. 첫 번째 오퍼레이션을 실행하기 전에 시작 상태를 확인하려면 wait()를 호출한 다음 status를 확인하세요.
실제로는 exec()가 내부적으로 RUNNING 상태가 될 때까지 기다리므로 이 부분이 문제가 되는 경우는 드뭅니다. wait()를 명시적으로 호출하면 시작 실패와 오퍼레이션 실패를 구분해서 처리하고 싶을 때 유용합니다.

샌드박스 대기

SDK는 시작 상태를 확인하거나 메인 명령이 완료될 때까지 기다리는 대기 방법을 제공합니다. 다음 섹션에서는 각 방법과 시작 timeout 및 오퍼레이션 timeout의 관계를 설명합니다.

wait(): 시작 상태가 될 때까지 대기

wait()는 PENDING, CREATING 같은 시작 상태가 진행되는 동안 폴링합니다. 예를 들어 샌드박스가 RUNNING 또는 TERMINATING 상태가 되거나 성공적으로 완료되면 반환할 수 있습니다:
폴링은 지수 백오프를 사용합니다: 0.2초 간격으로 시작하여 1.5배씩 스케일링하며, 2.0초에 한도를 적용합니다. wait()는 샌드박스 객체를 반환합니다. 실행 중인 샌드박스가 필요한 오퍼레이션을 호출하기 전에 status를 확인하세요. 정상적으로 반환되었다고 해서 RUNNING 상태가 보장되지는 않습니다. 샌드박스가 시작 중에 종료 상태에 도달하면, wait()가 이를 처리합니다:

wait_until_complete(): 터미널 상태까지 대기

wait_until_complete()는 샌드박스가 터미널 상태에 도달할 때까지 대기하며, TERMINATING 상태에서도 자동으로 폴링을 계속합니다. 메인 명령이 작업을 수행하는 샌드박스에 사용하세요:
기본값이 True인 raise_on_termination 매개변수는 이 클라이언트가 stop()을 호출했거나 레거시 백엔드가 TERMINATED를 보고한 후 wait_until_complete()가 SandboxTerminatedError를 발생시킬지 제어합니다. COMPLETED로 보고된 외부 중지는 이 오류를 발생시키지 않습니다. 응답에서 외부 중지와 정상 완료가 구분되지 않기 때문입니다. 반면 최대 수명에 도달한 샌드박스는 FAILED 상태로 종료되므로 wait_until_complete()가 SandboxFailedError를 발생시킵니다.

timeout 단계

시작 대기 시간과 오퍼레이션 timeout은 별개의 단계이며, 샌드박스의 최대 수명이 두 단계 모두를 제한합니다:
  • 시작 대기: 시작되거나 조기에 터미널 상태에 도달할 때까지 대기하는 시간입니다. wait()의 timeout 매개변수로 제어합니다.
  • 완료 대기: 터미널 상태에 도달할 때까지 대기하는 시간으로, 남은 시작 과정, 실행, 재시작 및 종료를 모두 포함합니다. wait_until_complete()의 timeout 매개변수로 제어합니다.
  • 오퍼레이션 timeout: 개별 실행, 조회 또는 쓰기에 허용되는 시간입니다. exec()의 timeout_seconds 또는 SandboxDefaults의 request_timeout_seconds로 제어합니다. 시작 대기는 포함하지 않습니다.
  • 최대 수명: 샌드박스가 존재할 수 있는 총 실제 경과 시간으로, 시작 시점부터 계산하며 시작 대기를 포함합니다. max_lifetime_seconds로 제어합니다. 설정하지 않으면 러너 정책의 기본값이 적용되며, 양수 기본값이 설정되어 있지 않으면 플랫폼의 대체 기본값인 10분이 적용됩니다.
시작, 완료 및 오퍼레이션 timeout은 클라이언트의 대기 시간을 제한하며, 만료되어도 샌드박스는 계속 실행됩니다. 최대 수명은 샌드박스 자체의 수명을 제한합니다. 만료되면 플랫폼이 샌드박스를 종료하고 진행 중인 오퍼레이션도 함께 실패합니다. max_lifetime_seconds를 예상되는 총 작업 시간보다 충분히 길게 설정하세요. 이 값은 샌드박스가 시작된 후에는 변경할 수 없습니다. timeout 설정과 상호 작용 방식은 timeout을 참조하세요. 30일 제한과 Serverless 및 CKS용 설정 예시는 장기 실행 샌드박스 실행을 참조하세요.

오퍼레이션 및 라이프사이클

exec(), read_file(), write_file() 등의 오퍼레이션은 필요한 경우 샌드박스를 자동으로 시작한 다음, RUNNING 상태가 될 때까지 기다린 후 진행합니다:
오퍼레이션 timeout(timeout_seconds)은 샌드박스가 RUNNING 상태가 된 후에만 적용됩니다. 시작 시간은 timeout에 포함되지 않습니다.

샌드박스 중지 및 수명 종료

이 섹션에서는 샌드박스를 종료하는 방법, 중지 후 발생하는 동작, 그리고 stop()과 delete()를 각각 언제 사용해야 하는지 설명합니다.

stop()

stop()은 중지 요청을 보내고 OperationRef[None]을 반환합니다. 샌드박스는 TERMINATING(유예 기간 동안 드레이닝) 상태를 거쳐 터미널 상태에 도달합니다. 반환된 OperationRef는 중지 RPC가 성공했을 때가 아니라 백엔드가 터미널 상태를 확인했을 때 완료됩니다:
매개변수: 종료 시 스냅샷 기능을 사용하려면 샌드박스가 file_system_snapshot 마운트로 시작되어야 하고, 조직에서 File System Snapshots(FSS)가 활성화되어 있어야 합니다. 이 기능은 샌드박스 파일 시스템 전체가 아니라 해당 마운트만 캡처합니다. 설정 방법은 파일 시스템 스냅샷을 참조하세요.
stop()은 진행 중인 시작 요청을 처리합니다. 시작 요청이 아직 처리 중이면 시작이 완료될 때까지 기다린 후 중지합니다. 동시에 수행되는 일반 stop() Call은 하나의 중지 오퍼레이션을 공유하며, 일반 중지를 반복해도 중복된 중지 RPC를 보내지 않습니다. snapshot_on_stop=True Call이 스냅샷을 캡처하지 않는 중지에 합류하거나 그런 중지를 관찰하게 되면 SnapshotOnStopConflictError 예외가 발생합니다. snapshot-on-stop은 일반 중지가 시작되기 전에 요청하세요.

중지 후 동작

stop()이 호출되면 샌드박스는 TERMINATING(유예 기간 동안 드레이닝하는 상태)을 거쳐 종료 상태(COMPLETED 또는 FAILED)에 도달합니다. stop()이 호출된 후에는 샌드박스를 사용할 수 없습니다. 이후 오퍼레이션은 SandboxNotRunningError를 발생시킵니다:
status 속성은 마지막 API 호출에서 캐시됩니다. 중지하기 전에 최신 데이터를 조회하려면 get_status()를 사용하세요:

컨텍스트 관리자 종료

컨텍스트 관리자는 종료 시 stop()을 자동으로 호출합니다:
예외가 진행 중인 경우, 컨텍스트 관리자는 원래 예외를 가리지 않기 위해 stop 오류를 억제합니다.

stop()와 delete() 비교

활성 상태로 사용 중인 샌드박스에는 stop()을 사용하세요. 샌드박스의 정리에는 delete()를 사용하세요. Sandbox.list() 또는 Sandbox.from_id()를 통해 발견한 샌드박스:
정리 패턴 가이드에서 고아 샌드박스 관리 및 일괄 정리 전략을 확인하세요.

내부 동작

SDK는 자체 asyncio 이벤트 루프가 있는 백그라운드 데몬 스레드에서 모든 gRPC 오퍼레이션을 실행합니다. 이 설계는 다음과 같이 동작합니다:
  • 동기 API (.result())는 백그라운드 루프가 네트워크 호출을 처리하는 동안 호출 스레드를 차단합니다.
  • 비동기 API (await)는 동일한 백그라운드 루프에 연결되므로 두 방식 모두 동일한 내부 구현을 사용합니다.
  • 백그라운드 루프는 처음 사용할 때 지연 시작됩니다. gRPC 채널도 지연 생성됩니다.
  • 자동 시작은 각 오퍼레이션 전에 sandbox_id가 None인지 확인하고, None이면 start()를 트리거하는 방식으로 동작합니다.
  • 프로세스가 종료되면 정리 핸들러(atexit + 시그널 핸들러)가 등록된 세션의 모든 샌드박스를 중지합니다. 정리 중 Ctrl+C를 한 번 더 누르면 즉시 강제 종료됩니다.
이 아키텍처는 서로 다른 이벤트 루프 간의 문제를 방지하며, Jupyter 노트북에서도 nest_asyncio 없이 작동합니다. 사용 방식은 동기 및 비동기 방식 비교 가이드를 참조하세요.

일반적인 패턴

다음 예시는 앞서 설명한 라이프사이클 단계를 조합한 엔드투엔드 패턴을 보여줍니다.

간단한 일회성 실행

명령을 실행하고 결과를 조회하세요. 컨텍스트 관리자가 정리 작업을 처리합니다:

제어된 시작

시작 오류와 오퍼레이션 오류를 분리하세요:

장시간 실행되는 샌드박스

메인 명령이 완료될 때까지 기다리세요:
샌드박스의 메인 명령이 종료되기 전에 파일을 가져오세요. 결과를 다운로드해야 하는 워크로드라면 메인 프로세스가 장시간 실행되는 샌드박스에서 exec()로 작업을 실행한 다음, 샌드박스를 중지하기 전에 파일을 읽으세요.

재연결

이전 세션 또는 프로세스에서 사용하던 샌드박스에 다시 연결합니다.

세션을 사용한 병렬 배치 처리

여러 샌드박스를 생성하고 결과를 기다립니다.
마지막 수정일 2026년 11월 4일