> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreweave.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Cleanup patterns

> Patterns for reliable sandbox cleanup and resource management.

이 예시에서는 `CWSANDBOX_API_KEY`에 설정된 CoreWeave API 액세스 토큰을 사용합니다. Forge API 키 인증은 [시작하기](/ko/products/sandboxes/get-started)를 참조하세요. CKS 요구 사항은 [배치 모드](/ko/products/sandboxes/placement)를 참조하세요.

이 가이드는 샌드박스의 리소스 관리 및 정리 전략을 다룹니다. 신뢰할 수 있는 정리는 스크립트 종료 후 고아 샌드박스를 방지하여 비용을 예측 가능하게 유지하고 의도하지 않은 컴퓨트 리소스 사용을 피합니다. 여기의 패턴은 명시적 세션 유무와 관계없이 하나 또는 여러 샌드박스를 생성하는 스크립트에 적용됩니다.

<h2 id="automatic-cleanup">
  자동 정리
</h2>

자동 정리는 샌드박스의 수명을 Python 구조(컨텍스트 관리자 또는 프로세스가 종료될 때 SDK가 닫는 세션)에 연결하여 SDK가 명시적인 `stop()` 호출 없이 리소스를 해제하도록 합니다. 세션이나 컨텍스트 관리자 밖에서 `Sandbox.run()`으로 시작한 샌드박스는 스크립트가 종료된 후에도 계속 실행됩니다. 이 샌드박스는 메인 명령이 종료되거나, 사용자가 직접 중지하거나, 최대 수명이 만료되어야 종료됩니다.

<h3 id="context-managers-recommended">
  컨텍스트 매니저 (권장)
</h3>

컨텍스트 매니저는 둘러싼 코드에서 예외가 발생하더라도 정리 작업을 보장하므로 권장되는 패턴입니다. SDK는 컨텍스트가 종료될 때 샌드박스를 중지합니다:

```python theme={"system"}
from cwsandbox import Sandbox

with Sandbox.run() as sandbox:
    result = sandbox.exec(["echo", "hello"]).result()
# sandbox.stop() 자동으로 호출됨
```

세션은 모든 샌드박스를 정리합니다:

```python theme={"system"}
import cwsandbox
from cwsandbox import SandboxDefaults

with cwsandbox.Session(SandboxDefaults(container_image="python:3.11")) as session:
    sb1 = session.sandbox()
    sb2 = session.sandbox()
# 두 샌드박스 모두 자동으로 중단됨
```

<h3 id="global-cleanup-handlers">
  글로벌 정리 핸들러
</h3>

SDK는 프로세스가 종료될 때 등록된 세션이 소유한 샌드박스를 중지하는 정리 핸들러를 등록합니다. 세션이나 컨텍스트 관리자 밖에서 생성한 독립형 샌드박스는 명시적으로 정리해야 합니다.

| 시나리오 | 동작 |
| - | - |
| 스크립트 정상 종료 | `atexit` 핸들러가 등록된 세션의 샌드박스를 중지합니다 |
| Ctrl+C (`SIGINT`) | 시그널 핸들러가 등록된 세션의 샌드박스를 중지합니다 |
| `SIGTERM` | 시그널 핸들러가 등록된 세션의 샌드박스를 중지합니다 |
| Ctrl+C 두 번 입력 | 강제 종료(종료 시 응답 없음 상태 방지) |

SDK는 코드에서 처음으로 샌드박스를 생성할 때 이 핸들러를 설치합니다. `SIGINT` 및 `SIGTERM` 핸들러는 Python 메인 스레드에서만 설치됩니다. 애플리케이션에서 시그널을 직접 관리하는 경우, 첫 번째 샌드박스를 생성하기 전에 `cwsandbox.disable_signal_handlers()`를 호출하거나 `CWSANDBOX_DISABLE_SIGNAL_HANDLERS=1`을 설정하세요. 이 경우에도 `atexit` 핸들러는 계속 실행되지만, 시그널을 수신했을 때 샌드박스를 중지하는 작업은 애플리케이션이 직접 처리해야 합니다.

<h2 id="manual-cleanup">
  수동 정리
</h2>

샌드박스나 세션을 해제하는 시점을 명시적으로 제어해야 할 때는 수동 정리를 사용하세요. 수동 정리를 사용하면 중지 옵션을 전달하거나 장시간 실행되는 코드 전반에서 정리 작업을 조율할 수 있습니다.

<h3 id="sandbox-stop">
  샌드박스 stop()
</h3>

```python theme={"system"}
sandbox = Sandbox.run()
result = sandbox.exec(["echo", "hello"]).result()
sandbox.stop().result()

# 옵션과 함께
sandbox.stop(graceful_shutdown_seconds=30.0).result()
sandbox.stop(snapshot_on_stop=True).result()
```

<h3 id="session-close">
  세션 close()
</h3>

```python theme={"system"}
from cwsandbox import SandboxDefaults

session = cwsandbox.Session(SandboxDefaults(container_image="python:3.11"))
sandbox = session.sandbox()
# ...
session.close().result()  # 모든 샌드박스를 중지합니다
```

<h3 id="batch-cleanup">
  배치 정리
</h3>

```python theme={"system"}
from cwsandbox import results

sandboxes = [Sandbox.run() for _ in range(5)]
# ... 샌드박스 사용 ...
results([sb.stop() for sb in sandboxes])  # 모두 병렬로 중지
```

<h2 id="orphan-management">
  고아 관리
</h2>

고아는 이를 생성한 프로세스가 종료된 후에도 의도치 않게 계속 실행되고 있는 샌드박스입니다. 의도적으로 계속 실행해 두는 독립형 샌드박스는 고아가 아니지만, 이를 놓쳐 추적하지 못하게 되면 고아가 됩니다. 다음 섹션에서는 고아를 쉽게 찾는 방법, 고아를 쿼리하는 방법, 그리고 관리되는 정리 하에 다시 가져오는 방법을 설명합니다.

<h3 id="tagging-for-discovery">
  검색을 위한 태그 지정
</h3>

세션 및 컨텍스트 관리자에서 실행되는 샌드박스는 SDK의 자동 정리 작업 덕분에 대부분 고아 샌드박스가 되지 않습니다. 하지만 강제 종료(`kill -9`)나 네트워크 장애가 발생하면 이러한 샌드박스도 계속 실행될 수 있습니다. 독립 실행형 샌드박스는 정리 핸들러가 중지하지 않으므로, 직접 중지하는 것을 잊으면 고아 샌드박스가 됩니다. 나중에 고아 샌드박스를 찾을 수 있도록 태그를 사용하세요.

```python theme={"system"}
from cwsandbox import Sandbox, SandboxDefaults

# 생성 시 태그 지정
defaults = SandboxDefaults(
    container_image="python:3.11",
    tags=("my-project", "batch-job-123"),
)

with Sandbox.run(defaults=defaults) as sandbox:
    result = sandbox.exec(["echo", "hello"]).result()
```

권장 태그 지정 방식:

* 프로젝트 또는 애플리케이션 이름 (`my-project`)
* 작업 또는 run 식별자 (`batch-job-123`, `run-2024-01-15`)
* 환경 (`dev`, `staging`, `prod`)

<h3 id="find-orphaned-sandboxes">
  고아 샌드박스 찾기
</h3>

태그로 쿼리하여 이전 run의 샌드박스를 찾으세요:

```python theme={"system"}
from cwsandbox import Sandbox

orphans = Sandbox.list(tags=["my-project"]).result()
for sandbox in orphans:
    sandbox.stop().result()
```

<h3 id="session-adoption">
  세션 관리에 편입
</h3>

고아 샌드박스를 세션 관리에 편입하면 해당 세션에 연결되어 세션이 수명을 관리합니다. 그러면 고아 샌드박스에도 새로 생성된 샌드박스와 동일한 자동 정리가 보장됩니다. `session.list()`는 세션의 기본 태그를 필터에 추가하므로 해당 태그가 있는 샌드박스만 찾습니다. 세션의 태그를 적용하지 않고 검색하려면 [세션 가이드](/ko/products/sandboxes/client/guides/sessions#adopt-external-sandboxes)에 나온 것처럼 `Sandbox.list()`를 사용한 다음 각 결과를 세션 관리에 편입하세요:

```python theme={"system"}
import cwsandbox
from cwsandbox import SandboxDefaults

with cwsandbox.Session(SandboxDefaults(container_image="python:3.11")) as session:
    orphans = session.list(tags=["my-project"]).result()
    for sandbox in orphans:
        session.adopt(sandbox)
# 세션 관리에 편입된 모든 샌드박스는 세션과 함께 정리됩니다
```

<h3 id="delete-by-id">
  ID로 삭제
</h3>

샌드박스의 ID를 이미 알고 있다면, 먼저 목록을 조회하거나 세션 관리에 편입하지 않고 직접 삭제할 수 있습니다:

```python theme={"system"}
from cwsandbox import Sandbox

Sandbox.delete("sandbox-abc123").result()
Sandbox.delete("sandbox-abc123", missing_ok=True).result()  # 없으면 무시
```
