# Jobs 실행 및 관리

Hugging Face Hub는 Jobs를 통해 AI 및 데이터 워크플로우에 대한 컴퓨트를 제공합니다.

**Jobs와 가격에 대한 일반적인 개요는 [Hub Jobs 문서](https://huggingface.co/docs/hub/jobs)를 참고하세요.**

Job은 Hugging Face 인프라에서 실행되며, 실행할 명령(예: python 명령), Hugging Face Spaces 또는 Docker Hub의 Docker Image, 그리고 하드웨어 flavor(CPU, GPU, TPU)로 정의됩니다. 이 가이드에서는 Hub에서 Job을 사용하는 방법을, 특히 다음을 중심으로 보여 드립니다:

- job을 실행합니다.
- 작업 상태를 확인합니다.
- 하드웨어를 선택합니다.
- 환경 변수와 시크릿을 구성합니다.
- UV 스크립트를 실행합니다.

Hub에서 작업을 실행하고 관리하려면 머신이 로그인되어 있어야 합니다. 로그인되어 있지 않다면 [이 섹션](../quick-start#authentication)을 참조하세요. 이 가이드의 나머지 부분에서는 머신이 로그인되어 있다고 가정합니다.

> [!TIP]
> **Hugging Face Jobs**는 [크레딧 잔액](https://huggingface.co/settings/billing)이 양수인 모든 사용자 또는 조직에서 사용할 수 있습니다. 자세한 내용은 [Jobs 가격 및 청구](https://huggingface.co/docs/hub/jobs-pricing)를 참조하세요.

## Jobs 명령줄 인터페이스

[`hf jobs` CLI](./cli#hf-jobs)를 사용하여 명령줄에서 Jobs를 실행하고, `--flavor`를 전달하여 하드웨어를 지정합니다.

`hf jobs run`은 Docker 이미지와 명령어를 사용하여 익숙한 Docker와 유사한 인터페이스로 Jobs를 실행합니다. `docker run`처럼 생각하되, 모든 하드웨어에서 코드를 실행하는 용도로 사용됩니다:

```bash
>>> hf jobs run --name hello-world python:3.12 python -c "print('Hello world')"
>>> hf jobs run --name gpu-check --flavor a10g-small pytorch/pytorch:2.6.0-cuda12.4-cudnn9-devel python -c "import torch; print(torch.cuda.get_device_name())"
```

`hf jobs uv run`를 사용하여 로컬 또는 원격 UV 스크립트를 실행합니다:

```bash
>>> hf jobs uv run --name my-script my_script.py
>>> hf jobs uv run --name sft-training --flavor a10g-small "https://raw.githubusercontent.com/huggingface/trl/main/trl/scripts/sft.py"
```

UV 스크립트는 [UV 문서](https://docs.astral.sh/uv/guides/scripts/)에서 정의한 특수한 주석 문법을 사용하여 파일 내에 직접 의존성을 포함하는 Python 스크립트입니다.

이제 나머지 가이드에서는 Python API를 보여드립니다. 대신 사용 가능한 모든 `hf jobs` 명령어와 옵션을 확인하려면 [`hf jobs` 명령줄 인터페이스 가이드](./cli#hf-jobs)를 참고하세요.

> [!TIP]
> Need an *interactive* machine instead of a fire-and-forget job — e.g. to run AI-generated code, with command execution and file transfer? Check out [Sandboxes](./sandbox), built on top of Jobs.

## Job 실행

명령어와 Docker Image로 정의된 compute Jobs를 Hugging Face 인프라(GPU 및 TPU 포함)에서 실행합니다.

사용자가 소유한 Job(사용자 이름 네임스페이스 아래) 또는 쓰기 권한이 있는 조직의 Job만 관리할 수 있습니다. 이 기능은 사용량 과금 방식입니다. 사용한 초당만 요금이 부과됩니다.

[run_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.run_job)을 사용하면 Hugging Face 인프라에서 원하는 명령을 실행할 수 있습니다:

```python
# Directly run Python code
>>> from huggingface_hub import run_job
>>> run_job(
...     image="python:3.12",
...     command=["python", "-c", "print('Hello from the cloud!')"],
... )

# Use GPUs without any setup
>>> run_job(
...     image="pytorch/pytorch:2.6.0-cuda12.4-cudnn9-devel",
...     command=["python", "-c", "import torch; print(torch.cuda.get_device_name())"],
...     flavor="a10g-small",
... )

# Run in an organization account
>>> run_job(
...     image="python:3.12",
...     command=["python", "-c", "print('Running in an org account')"],
...     namespace="my-org-name",
... )

# Run from Hugging Face Spaces
>>> run_job(
...     image="hf.co/spaces/lhoestq/duckdb",
...     command=["duckdb", "-c", "select 'hello world'"],
... )

# Run a Python script with `uv` (experimental)
>>> from huggingface_hub import run_uv_job
>>> run_uv_job("my_script.py")
```

> [!WARNING]
> **중요**: Job에는 기본 타임아웃(30분)이 설정되어 있으며, 해당 시간이 지나면 자동으로 중단됩니다. 모델 학습과 같은 장기 실행 작업의 경우, `timeout` 매개변수를 사용하여 사용자 지정 타임아웃을 설정해야 합니다. 자세한 내용은 [Job 타임아웃 구성](#configure-job-timeout)을 참조하세요.

[run_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.run_job)은 Hugging Face에서 Job의 URL을 포함하는 [JobInfo](/docs/huggingface_hub/v2.4.0/ko/package_reference/jobs#huggingface_hub.JobInfo)를 반환하며, 여기서 Job 상태와 로그를 확인할 수 있습니다. [JobInfo](/docs/huggingface_hub/v2.4.0/ko/package_reference/jobs#huggingface_hub.JobInfo)에서 Job ID를 저장하여 작업을 관리하세요:

```python
>>> from huggingface_hub import run_job
>>> job = run_job(
...     image="python:3.12",
...     command=["python", "-c", "print('Hello from the cloud!')"]
... )
>>> job.url
https://huggingface.co/jobs/lhoestq/687f911eaea852de79c4a50a
>>> job.id
687f911eaea852de79c4a50a
```

Jobs는 백그라운드에서 실행됩니다. 다음 섹션에서는 [inspect_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.inspect_job)을 사용하여 Job의 상태를 확인하고, [fetch_job_logs()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.fetch_job_logs)을 사용하여 로그를 표시하며, [fetch_job_metrics()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.fetch_job_metrics)을 사용하여 리소스 사용량을 모니터링하는 방법을 안내합니다.

## Job 재시도 및 재실행

`attempts`를 사용하여 실패한 Job을 재시도합니다. 이 숫자는 초기 시도를 포함하므로 `attempts=3`이면 최대 두 번까지 재시도할 수 있습니다. `run_uv_job`, `create_scheduled_job`, `create_scheduled_uv_job`에서도 사용할 수 있습니다.

```python
>>> from huggingface_hub import rerun_job, run_job
>>> job = run_job(image="python:3.12", command=["python", "train.py"], attempts=3)
>>> job.retry
2

# Start a new Job with the same spec, including its retry setting
>>> new_job = rerun_job(job_id=job.id)
```

`rerun_job`은 새로운 ID를 가진 별도의 Job을 시작합니다. 완료되거나 실패한 Job에 적용되며, secrets와 하드웨어 설정을 포함한 저장된 spec을 재사용합니다. `hf jobs rerun <job_id>`을 실행하는 것도 가능합니다.

## Job 상태 확인

```python
# List your jobs (results are paginated and returned as an iterator)
>>> from huggingface_hub import list_jobs
>>> jobs = list_jobs()
>>> next(iter(jobs))
JobInfo(id='687f911eaea852de79c4a50a', created_at=datetime.datetime(2025, 7, 22, 13, 24, 46, 909000, tzinfo=datetime.timezone.utc), docker_image='python:3.12', space_id=None, command=['python', '-c', "print('Hello from the cloud!')"], arguments=[], environment={}, secrets={}, flavor='cpu-basic', status=JobStatus(stage='COMPLETED', message=None), owner=JobOwner(id='5e9ecfc04957053f60648a3e', name='lhoestq'), endpoint='https://huggingface.co', url='https://huggingface.co/jobs/lhoestq/687f911eaea852de79c4a50a')

# Materialize the iterator into a list
>>> all_jobs = [job for job in list_jobs()]

# List your running jobs
>>> running_jobs = list_jobs(status="RUNNING")

# Filter by one or more statuses and/or labels
>>> list_jobs(status=["RUNNING", "SCHEDULING"], labels={"env": "prod"})

# Inspect the status of a job
>>> from huggingface_hub import inspect_job
>>> inspect_job(job_id=job_id)
JobInfo(id='687f911eaea852de79c4a50a', created_at=datetime.datetime(2025, 7, 22, 13, 24, 46, 909000, tzinfo=datetime.timezone.utc), docker_image='python:3.12', space_id=None, command=['python', '-c', "print('Hello from the cloud!')"], arguments=[], environment={}, secrets={}, flavor='cpu-basic', status=JobStatus(stage='COMPLETED', message=None), owner=JobOwner(id='5e9ecfc04957053f60648a3e', name='lhoestq'), endpoint='https://huggingface.co', url='https://huggingface.co/jobs/lhoestq/687f911eaea852de79c4a50a')

# View logs from a job
>>> from huggingface_hub import fetch_job_logs
>>> for log in fetch_job_logs(job_id=job_id):
...     print(log)
Hello from the cloud!

# View resources usage metrics from a job
>>> from huggingface_hub import fetch_job_metrics
>>> for metrics in fetch_job_metrics(job_id=job_id):
...     print(metrics)
{
    "cpu_usage_pct": 0,
    "cpu_millicores": 2000,
    "memory_used_bytes": 929792,
    "memory_total_bytes": 17179869184,
    "rx_bps": 0,
    "tx_bps": 0,
    "gpus": {},
    "replica": "4dzsh"
}

# Cancel a job
>>> from huggingface_hub import cancel_job
>>> cancel_job(job_id=job_id)
```

## Jobs가 완료될 때까지 기다립니다

Job이 종료 단계(`COMPLETED`, `CANCELED`, `ERROR` 또는 `DELETED`)에 도달할 때까지 블로킹하려면 [wait_for_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.wait_for_job)를 사용하세요. 최종 [JobInfo](/docs/huggingface_hub/v2.4.0/ko/package_reference/jobs#huggingface_hub.JobInfo)는 항상 반환되며, 실패한 Job은 예외를 발생시키지 않으므로 결과를 처리하려면 `job.status.stage`를 확인해야 합니다. Job ID 목록을 전달하면 배치 전체를 한 번에 대기할 수 있습니다.

```python
>>> from huggingface_hub import run_job, wait_for_job
>>> job = run_job(image="python:3.12", command=["python", "-c", "print('hello')"])
>>> wait_for_job(job_id=job.id).status.stage
'COMPLETED'

# Run multiple jobs in parallel and wait for all of them to finish
>>> jobs = [run_job(image=image, command=command) for command in commands]
>>> finished_jobs = wait_for_job(job_id=[job.id for job in jobs], timeout=3600)
```

CLI에서도 `hf jobs wait`로 동일한 기능을 사용할 수 있으며, 모든 Job이 성공적으로 완료된 경우에만 종료 코드 0을 반환합니다. 셸 스크립트나 CI에서 명령을 연쇄 실행할 때 유용합니다:

```bash
# Chain on success
hf jobs wait <job_id> && hf jobs run --detach python:3.12 python eval.py

# Wait for all currently running jobs
hf jobs ls -q | xargs hf jobs wait
```

Job이 실패하면 0이 아닌 코드로 종료되므로, 비디텍치드 `hf jobs run` (또는 `hf jobs uv run`)의 경우에도 `hf jobs run ... && next-step`이 명시적인 대기 없이 올바르게 체인됩니다.

## 하드웨어 선택

GPU에서 Jobs를 실행하는 것이 유용한 경우는 다음과 같습니다:

- **모델 학습**: 인프라를 관리하지 않고 GPU(T4, A10G, A100)에서 모델을 파인튜닝하거나 학습합니다
- **합성 데이터 생성**: 강력한 하드웨어에서 LLM을 사용하여 대규모 데이터셋 생성
- **데이터 처리**: 대규모 데이터셋을 병렬 워크로드를 위해 고 CPU 구성으로 처리
- **배치 추론**: 최적화된 GPU 구성을 사용하여 수천 개의 샘플에 대해 오프라인 추론을 실행
- **실험 및 벤치마크**: 재현 가능한 결과를 위해 일관된 하드웨어에서 ML 실험을 실행합니다
- **개발 및 디버깅**: 로컬 CUDA 설정 없이 GPU 코드 테스트

`flavor` 인수를 사용하여 GPU 또는 TPU에서 작업을 실행합니다. 예를 들어, A10G GPU에서 PyTorch 작업을 실행하려면:

```python
# Use an A10G GPU to check PyTorch CUDA
>>> from huggingface_hub import run_job
>>> run_job(
...     image="pytorch/pytorch:2.6.0-cuda12.4-cudnn9-devel",
...     command=["python", "-c", "import torch; print(f'This code ran with the following GPU: {torch.cuda.get_device_name()}')"],
...     flavor="a10g-small",
... )
```

이것을 실행하면 다음과 같은 출력이 표시됩니다!

```bash
This code ran with the following GPU: NVIDIA A10G
```

UV로 [trl/scripts/sft.py](https://github.com/huggingface/trl/blob/main/trl/scripts/sft.py)와 같은 파인튜닝 스크립트를 실행하려면 다음을 사용하세요:

```python
>>> from huggingface_hub import run_uv_job
>>> run_uv_job(
...     "sft.py",
...     script_args=["--model_name_or_path", "Qwen/Qwen2-0.5B", ...],
...     dependencies=["trl"],
...     env={"HF_TOKEN": ...},
...     flavor="a10g-small",
... )
```

> [!TIP]
> Hugging Face 인프라에서 TRL로 모델 학습 작업을 실행하는 방법에 대한 종합적인 가이드는 [TRL Jobs Training 문서](https://huggingface.co/docs/trl/main/en/jobs_training)를 참고하세요. 이 문서에는 파인튜닝 레시피, 하드웨어 선택, 그리고 모델을 효율적으로 학습하기 위한 모범 사례가 포함되어 있습니다.

Jobs를 실행할 수 있는 사용 가능한 하드웨어 전체 목록은 다음과 같습니다:

| 이름 | 이름 | cpu | ram | 저장 | accelerator | 비용/분 | 시간당 비용 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `cpu-basic` | CPU 기본 | 2 vCPU | 16 GB | 50 GB | - | $0.0002 | $0.01 |
| `cpu-upgrade` | CPU 업그레이드 | 8 vCPU | 32 GB | 50 GB | - | $0.0005 | $0.03 |
| `cpu-performance` | CPU 성능 | 32 vCPU | 256 GB | 1024 GB | - | $0.0317 | $1.90 |
| `cpu-xl` | CPU XL | 16 vCPU | 124 GB | 1000 GB | - | $0.0167 | $1.00 |
| `t4-small` | Nvidia T4 - 소형 | 4 vCPU | 15 GB | 50 GB | T4 1개 (16 GB) | $0.0067 | $0.40 |
| `t4-medium` | Nvidia T4 - 중간 | 8 vCPU | 30 GB | 100 GB | T4 1개 (16 GB) | $0.0100 | $0.60 |
| `a10g-small` | Nvidia A10G - 소형 | 4 vCPU | 15 GB | 110 GB | A10G (24 GB) 1개 | $0.0167 | $1.00 |
| `a10g-large` | Nvidia A10G - 대형 | 12 vCPU | 46 GB | 200 GB | A10G (24 GB) 1개 | $0.0250 | $1.50 |
| `a10g-largex2` | 2x Nvidia A10G - 대형 | 24 vCPU | 92 GB | 1000 GB | 2x A10G (48 GB) | $0.0500 | $3.00 |
| `a10g-largex4` | 4x Nvidia A10G - 대형 | 48 vCPU | 184 GB | 2000 GB | 4x A10G (96 GB) | $0.0833 | $5.00 |
| `a100-large` | Nvidia A100 - 대형 | 12 vCPU | 142 GB | 1000 GB | A100 (80 GB) 1개 | $0.0417 | $2.50 |
| `a100x4` | Nvidia A100 4개 | 48 vCPU | 568 GB | 4000 GB | 4x A100 (320 GB) | $0.1667 | $10.00 |
| `a100x8` | 8x Nvidia A100 | 96 vCPU | 1136 GB | 8000 GB | 8x A100 (640 GB) | $0.3333 | $20.00 |
| `h200` | Nvidia H200 | 23 vCPU | 256 GB | 3000 GB | 1x H200 (141 GB) | $0.0833 | $5.00 |
| `h200x2` | Nvidia H200 | 46 vCPU | 512 GB | 6000 GB | 2x H200 (282 GB) | $0.1667 | $10.00 |
| `h200x4` | Nvidia H200 | 92 vCPU | 1024 GB | 12000 GB | 4x H200 (564 GB) | $0.3333 | $20.00 |
| `h200x8` | Nvidia H200 | 184 vCPU | 2048 GB | 24000 GB | 8x H200 (1128 GB) | $0.6667 | $40.00 |
| `rtx-pro-6000` | Nvidia RTX PRO 6000 | 23 vCPU | 256 GB | 475 GB | 1x RTX PRO 6000 (96 GB) | $0.0458 | $2.75 |
| `rtx-pro-6000x2` | Nvidia RTX PRO 6000 | 46 vCPU | 512 GB | 950 GB | 2x RTX PRO 6000 (192 GB) | $0.0917 | $5.50 |
| `rtx-pro-6000x4` | Nvidia RTX PRO 6000 | 92 vCPU | 1024 GB | 1900 GB | 4x RTX PRO 6000 (384 GB) | $0.1833 | $11.00 |
| `rtx-pro-6000x8` | Nvidia RTX PRO 6000 | 184 vCPU | 2048 GB | 3800 GB | 8x RTX PRO 6000 (768 GB) | $0.3667 | $22.00 |
| `l4x1` | Nvidia L4 1개 | 8 vCPU | 30 GB | 400 GB | L4 1개 (24 GB) | $0.0133 | $0.80 |
| `l4x4` | Nvidia L4 4개 | 48 vCPU | 186 GB | 3200 GB | 4x L4 (96 GB) | $0.0633 | $3.80 |
| `l40sx1` | Nvidia L40S 1개 | 8 vCPU | 62 GB | 380 GB | L40S 1개 (48 GB) | $0.0300 | $1.80 |
| `l40sx4` | Nvidia L40S 4개 | 48 vCPU | 382 GB | 3200 GB | 4x L40S (192 GB) | $0.1383 | $8.30 |
| `l40sx8` | 8x Nvidia L40S | 192 vCPU | 1534 GB | 6500 GB | 8x L40S (384 GB) | $0.3917 | $23.50 |

다음 명령을 실행하여 이 목록을 프로그래밍 방식으로 가져올 수 있습니다:

```bash
>>> hf jobs hardware
```

또는 Python API를 사용하여:

```python
>>> from huggingface_hub import list_jobs_hardware
>>> list_jobs_hardware()
```

이것으로 끝입니다! 이제 Hugging Face의 인프라에서 코드를 실행하고 있습니다.

## 볼륨 마운트

[Volume](/docs/huggingface_hub/v2.4.0/ko/package_reference/jobs#huggingface_hub.Volume) 목록을 사용하여 Jobs의 디스크에 볼륨을 마운트합니다.

Hugging Face 리포지토리(모델/데이터셋/스페이스) 또는 [Storage Bucket](/docs/hub/storage-buckets)를 마운트할 수 있습니다. 예를 들어:

* 모델 저장소 마운트: `Volume(type="model", source="openai/gpt-oss-120b", mount_path="/model")`
* 데이터셋 저장소를 마운트: `Volume(type="dataset", source="HuggingFaceFW/fineweb", mount_path="/data")`
* 스토리지 버킷 마운트: `Volume(type="bucket", source="username/my-bucket", mount_path="/mnt")`

그런 다음 마운트된 볼륨을 로컬 디렉터리로 사용할 수 있습니다:

```python
>>> from huggingface_hub import run_job, Volume
>>> job = run_job(
...     image="duckdb/duckdb",
...     command=["duckdb", "-c", "SELECT * FROM '/data/**/*.parquet' LIMIT 5"],
...     volumes=[Volume(type="dataset", source="HuggingFaceFW/fineweb", mount_path="/data")],
... )
```

마운트된 버킷에 쓸 수도 있습니다. 예를 들어, 모델을 학습하는 동안 체크포인트를 저장하는 용도로 사용할 수 있습니다:

```python
>>> from huggingface_hub import run_uv_job, Volume
>>> script = "my_sft.py"
>>> script_args = ["--output_dir", "/training-outputs/training-v3-final", ...]
>>> checkpoints_bucket = Volume(type="bucket", source="username/my-bucket", mount_path="/training-outputs")
>>> run_uv_job(script, script_args=script_args, volumes=[checkpoints_bucket])
```

기본적으로 마운트된 스토리지 버킷은 읽기 및 쓰기 권한을 가집니다. 이는 데이터가 자주 변경되는 경우를 위해 빠르고 변경 가능한 스토리지를 제공하는 스토리지 버킷에 특히 유용하며, 파일을 원위치에서 덮어쓰기하거나 삭제할 수 있습니다.

읽기 전용을 활성화하려면 `read_only=True`를 사용하세요: `Volume(type="bucket", read_only=True, ...)`.

### 로컬 데이터 마운트

로컬 머신의 데이터를 대상으로 Job을 실행하려면 [sync_job_volume()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.sync_job_volume)를 사용하세요. 이 함수는 로컬 디렉토리를 `jobs-artifacts` [Storage Bucket](https://huggingface.co/docs/hub/storage-buckets)(필요 시 자동으로 생성됨)에 동기화하고 마운트할 준비가 된 [Volume](/docs/huggingface_hub/v2.4.0/ko/package_reference/jobs#huggingface_hub.Volume)을 반환합니다:

```python
>>> from huggingface_hub import run_uv_job, sync_job_volume

# Upload ./training-data once...
>>> volume = sync_job_volume("./training-data", "/data")

# ...then run as many Jobs as you want against it
>>> run_uv_job("train.py", script_args=["--learning-rate", "0.01"], volumes=[volume])
>>> run_uv_job("train.py", script_args=["--learning-rate", "0.05"], volumes=[volume])
```

각 디렉터리는 버킷에서 고유한 안정적인 폴더를 사용합니다. 동일한 디렉터리에 대해 [sync_job_volume()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.sync_job_volume)을 다시 실행해도 새로 추가되거나 수정된 파일만 업로드됩니다. 볼륨은 기본적으로 읽기 전용으로 마운트됩니다.

Job이 작성한 파일을 가져오려면 읽기/쓰기 볼륨(빈 출력 디렉터리도 사용 가능)을 마운트한 후, Job이 종료되면 해당 볼륨을 다시 동기화하세요:

```python
>>> from huggingface_hub import run_uv_job, sync_bucket, sync_job_volume

>>> outputs = sync_job_volume("./outputs", "/outputs", read_only=False)
>>> job = run_uv_job("process.py", volumes=[outputs])

# ...once the Job completes, pull back the data:
>>> sync_bucket(f"hf://buckets/{outputs.source}/{outputs.path}", "./outputs")
```

CLI에서 `-v`의 소스 측으로 로컬 디렉토리를 전달하면 됩니다:

```bash
>>> hf jobs uv run -v ./pdfs:/input -v ./md-out:/output:rw ocr.py
```

## Job 포트 노출

Jobs 프록시를 통해 컨테이너 포트에 접근할 수 있도록 하려면 `expose`를 전달하세요. 접근하려면 Job의 namespace에 대한 읽기 권한이 있는 HF 토큰이 필요합니다. 인증 없이 접근을 허용하려면 대신 `expose_public`을 사용하세요:

```python
>>> from huggingface_hub import run_job, update_job_expose
>>> job = run_job(
...     image="python:3.12",
...     command=["python", "-m", "http.server", "8000"],
...     expose_public=[8000],
... )
>>> job.expose_public
[8000]

# Keep the port exposed, but require an HF token from now on
>>> job = update_job_expose(job_id=job.id, expose=[8000])

# Close all exposed ports
>>> job = update_job_expose(job_id=job.id)
```

`expose`와 `expose_public`는 함께 사용할 수 있습니다. `update_job_expose`는 재시작 없이 실행 중인 Job의 전체 포트 구성을 대체하며, 두 목록에 모두 없는 포트는 닫힙니다. 두 옵션은 UV 및 예약 Job을 생성할 때도 사용할 수 있습니다.

## Job에 SSH로 접속

`ssh=True`를 [run_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.run_job)(또는 [run_uv_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.run_uv_job))에 전달하여 Job 컨테이너를 SSH로 접근 가능하게 만듭니다. SSH 엔드포인트는 Job 상태에 표시됩니다:

```python
>>> from huggingface_hub import run_job
>>> job = run_job(
...     image="python:3.12",
...     command=["sleep", "infinity"],
...     ssh=True,
... )
>>> job.status.ssh_url
'ssh://68498e23210b3a4f4e6e2a23@ssh.hf.jobs'
```

터미널에서 `hf jobs ssh <job_id>`(또는 `ssh <job_id>@ssh.hf.jobs`로 직접) 연결합니다:

```bash
>>> hf jobs ssh 68498e23210b3a4f4e6e2a23
```

Job의 namespace에 쓰기 권한이 있는 사용자만(즉, Job 생성자 또는 소유 조직의 멤버) https://huggingface.co/settings/keys에 등록된 SSH 공개 키로 인증되어 접근할 수 있습니다.

## 네트워크 그룹

`network_group="<name>"`을 [run_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.run_job)(또는 [run_uv_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.run_uv_job))에 전달하면 같은 namespace와 resource group에 있는 Jobs가 모든 포트에서 서로 통신할 수 있습니다. 각 멤버 내부에서 `HF_NETWORK_GROUP_HOSTNAME`은 그룹의 모든 Job으로 해석되며, `${HF_NETWORK_GROUP_PREFIX}<alias>`는 `network_aliases=[...]`로 alias를 선언한 멤버로 해석됩니다:

```python
>>> from huggingface_hub import run_job
>>> server = run_job(
...     image="python:3.12",
...     command=["python", "-m", "http.server", "8000"],
...     network_group="train",
...     network_aliases=["master"],
... )
>>> client = run_job(
...     image="python:3.12",
...     command=["sh", "-c", 'curl --retry 10 --retry-connrefused "http://${HF_NETWORK_GROUP_PREFIX}master:8000/"'],
...     network_group="train",
... )
>>> server.network
JobNetwork(group='train', aliases=['master'])
```

멤버는 준비가 완료되기 전에도 해석될 수 있으므로, 재시도(retry)를 사용하여 연결하세요. 그룹 이름과 별칭은 소문자 영숫자 및 대시(-)로만 구성되며, 최대 길이는 각각 46자 및 34자입니다.

## 작업 시간 초과 구성

Jobs에는 기본 타임아웃(30분)이 있으며, 이 시간이 지나면 자동으로 중지됩니다. 모델 학습과 같은 장기 실행 작업을 수행할 때 이 점을 알아두는 것이 중요합니다.

### 사용자 지정 타임아웃 설정

`timeout` 매개변수를 사용하여 작업을 실행할 때 사용자 지정 타임아웃 값을 지정할 수 있습니다. 타임아웃은 두 가지 방식으로 지정할 수 있습니다:

1. **숫자** (초로 해석):
```python
>>> from huggingface_hub import run_job
>>> job = run_job(
...     image="pytorch/pytorch:2.6.0-cuda12.4-cudnn9-devel",
...     command=["python", "train_model.py"],
...     flavor="a10g-large",
...     timeout=7200,  # 2 hours in seconds
... )
```

2. **시간 단위를 가진 문자열로**:
```python
>>> # Using different time units
>>> job = run_job(
...     image="pytorch/pytorch:2.6.0-cuda12.4-cudnn9-devel",
...     command=["python", "train_model.py"],
...     flavor="a10g-large",
...     timeout="2h",  # 2 hours
... )

>>> # Other examples:
>>> # timeout="30m"    # 30 minutes
>>> # timeout="1.5h"   # 1.5 hours
>>> # timeout="1d"     # 1 day
>>> # timeout="3600s"  # 3600 seconds
```

지원되는 시간 단위:
- `s` - 초
- `m` - 분
- `h` - 시간
- `d` - 일

### UV 작업에서 timeout 사용

UV 작업의 경우, 타임아웃도 지정할 수 있습니다:

```python
>>> from huggingface_hub import run_uv_job
>>> job = run_uv_job(
...     "training_script.py",
...     flavor="a10g-large",
...     timeout="90m",  # 90 minutes
... )
```

> [!WARNING]
> timeout을 지정하지 않으면 작업에 기본 timeout이 적용됩니다. 수 시간 이상 걸릴 수 있는 모델 학습과 같은 장기 실행 작업의 경우, 예상치 못한 작업 종료를 방지하기 위해 적절한 timeout을 설정하세요.

### 작업 시간 모니터링

긴 작업을 실행할 때 다음을 수행하는 것이 좋습니다:
- job의 예상 실행 시간을 추정하고, 여유 시간을 포함하여 timeout을 설정하세요
- 로그를 통해 작업 진행 상황을 모니터링합니다
- 작업이 시간 초과되지 않았는지 확인하려면 작업 상태를 확인하세요

```python
>>> from huggingface_hub import inspect_job, fetch_job_logs
>>> # Check job status
>>> job_info = inspect_job(job_id=job.id)
>>> if job_info.status.stage == "ERROR":
...     print(f"Job failed: {job_info.status.message}")
...     # Check logs for more details
...     for log in fetch_job_logs(job_id=job.id):
...         print(log)
```

timeout 파라미터에 대한 자세한 내용은 [`run_job` API 참고 문서를](https://huggingface.co/docs/huggingface_hub/package_reference/hf_api#huggingface_hub.HfApi.run_job.timeout) 참조하세요.

## 환경 변수 및 Secrets 전달

`env`와 `secrets`를 사용하여 작업에 환경 변수를 전달할 수 있습니다:

```python
# Pass environment variables
>>> from huggingface_hub import run_job
>>> run_job(
...     image="python:3.12",
...     command=["python", "-c", "import os; print(os.environ['FOO'], os.environ['BAR'])"],
...     env={"FOO": "foo", "BAR": "bar"},
... )
```

```python
# Pass secrets - they will be encrypted server side
>>> from huggingface_hub import run_job
>>> run_job(
...     image="python:3.12",
...     command=["python", "-c", "import os; print(os.environ['MY_SECRET'])"],
...     secrets={"MY_SECRET": "psswrd"},
... )
```

### 내장 환경 변수

컨테이너 내부에서 다음 환경 변수가 자동으로 사용 가능합니다:

| 변수 | 설명 |
|----------|-------------|
| `JOB_ID` | 현재 작업의 고유 식별자입니다. 이를 사용하여 작업을 프로그래매틱하게 참조할 수 있으며, 예를 들어 고유한 이름으로 데이터셋에 출력을 저장하는 데 사용할 수 있습니다. |
| `ACCELERATOR` | 사용 가능한 가속기의 유형(예: `t4-medium`, `a10g-small`, `a100x4`). 가속기가 없으면 비어 있습니다. |
| `CPU_CORES` | 작업에 사용할 수 있는 CPU 코어의 수 (예: `2`, `4`, `8`). |
| `MEMORY` | 작업에 사용할 수 있는 메모리 양(예: `16Gi`, `32Gi`). |

```python
# Access job environment information
>>> from huggingface_hub import run_job
>>> run_job(
...     image="python:3.12",
...     command=["python", "-c", """
... import os
... print(f"Job ID: {os.environ.get('JOB_ID')}")
... print(f"Accelerator: {os.environ.get('ACCELERATOR', 'none')}")
... print(f"CPU cores: {os.environ.get('CPU_CORES')}")
... print(f"Memory: {os.environ.get('MEMORY')}")
... """],
... )
```

이 변수들은 출력을 위한 고유 식별자를 생성하거나, 사용 가능한 하드웨어에 따라 코드를 조정하거나, 리소스 정보를 기록할 필요가 있을 때 유용합니다.

## 레이블

Labels는 Job에 메타데이터를 연결하는 key=value 쌍입니다:

UI에서 Jobs를 더 쉽게 찾고 식별할 수 있도록 `name`을 사용하세요. 이름은 선택 사항이며 고유할 필요가 없습니다:

```python
>>> from huggingface_hub import run_job
>>> run_job(name="daily-report", image="python:3.12", command=["python", "report.py"])
```

CLI에서 `--name`를 전달하여 Job을 생성하거나, labels 명령을 통해 기존 Job에 이름을 지정합니다:

```bash
>>> hf jobs run --name daily-report python:3.12 python report.py
>>> hf jobs labels <job_id> --name daily-report
```

`hf jobs ls`는 `NAME` 열을 표시하며 이름으로 필터링할 수 있습니다(`--label name=NAME`의 단축어):

```bash
>>> hf jobs ls -a --name daily-report
```

```python
# Pass extra metadata with Labels
>>> from huggingface_hub import run_job
>>> run_job(
...     image="python:3.12",
...     command=["python", "-c", "import os; print(os.environ['MY_SECRET'])"],
...     labels={"my-label": "my-value", "foo": "bar"},
... )
```

이름을 전달하지 않으면 Docker 이미지 또는 스크립트에서 자동으로 이름이 유도되며 짧은 해시가 추가됩니다(예: `python:3.12 foo --truc` → `python-3-12-1a2b3c4d`). CLI에서는 해당 해시가 명령*과* 해석된 런타임 설정(플래버, 타임아웃, 환경 값 등)을 모두 포함하므로 동일한 구성은 항상 동일한 이름을 생성합니다. 설정을 변경하면 이름도 변경되며, 스크립트의 `[tool.hf-jobs]` 헤더에서 가져온 설정도 포함됩니다. Python API에서는 해시가 명령만 포함합니다.

### 레이블 업데이트

[update_job_labels()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.update_job_labels)를 사용하여 기존 작업의 라벨을 교체합니다. 이 작업은 모든 기존 사용자 지정 라벨을 대체합니다:

```python
>>> from huggingface_hub import update_job_labels
>>> update_job_labels(job_id=job_id, labels={"env": "prod", "team": "ml"})
```

This also works for scheduled jobs with [update_scheduled_job_labels()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.update_scheduled_job_labels):

```python
>>> from huggingface_hub import update_scheduled_job_labels
>>> update_scheduled_job_labels(scheduled_job_id=scheduled_job_id, labels={"env": "staging"})
```

CLI에서:

```bash
>>> hf jobs labels <job_id> --label env=prod --label team=ml
>>> hf jobs scheduled labels <scheduled_job_id> --label env=staging
```

모든 라벨을 제거하려면 `--clear`를 전달하세요:

```bash
>>> hf jobs labels <job_id> --clear
```

## UV 스크립트 (실험적)

> [!TIP]
> 바로 사용할 수 있는 UV 스크립트를 찾고 계신가요? Hugging Face Hub의 [uv-scripts organization](https://huggingface.co/uv-scripts)을 확인해 보세요. 모델 학습, 합성 데이터 생성, 데이터 처리 등 다양한 작업을 위한 커뮤니티 기반 UV 스크립트 컬렉션을 제공합니다.

HF 인프라에서 UV 스크립트(인라인 의존성이 포함된 Python 스크립트)를 실행합니다:

```python
# Run a UV script (creates temporary repo)
>>> from huggingface_hub import run_uv_job
>>> run_uv_job("my_script.py")

# Run with GPU
>>> run_uv_job("ml_training.py", flavor="gpu-t4-small")

# Run with dependencies
>>> run_uv_job("inference.py", dependencies=["transformers", "torch"])

# Run a script directly from a URL
>>> run_uv_job("https://huggingface.co/datasets/username/scripts/resolve/main/example.py")

# Run a command
>>> run_uv_job("python", script_args=["-c", "import lighteval"], dependencies=["lighteval"])
```

UV 스크립트는 특수한 주석 문법을 사용하여 의존성을 파일 내에 직접 포함하는 Python 스크립트입니다. 이는 복잡한 프로젝트 설정이 필요하지 않은 자체 완결형 작업에 적합합니다. [UV 문서](https://docs.astral.sh/uv/guides/scripts/)에서 UV 스크립트에 대해 자세히 알아보세요.

#### launch config를 스크립트와 함께 배포

특정 런타임에서만 올바르게 실행되는 스크립트는 PEP 723 헤더의 선택적 `[tool.hf-jobs]` 테이블에 해당 런타인을 포함할 수 있습니다:

```python
# /// script
# requires-python = ">=3.11"
# dependencies = ["vllm", "datasets"]
#
# [tool.hf-jobs]
# image   = "vllm/vllm-openai:unlimited-ocr"
# flavor  = "l4x1"
# python  = "/usr/bin/python3"
# secrets = ["HF_TOKEN"]
# ///
```

`hf jobs uv run ocr.py`를 실행하면 올바른 이미지, 하드웨어 및 인터프리터로 시작되며, `--flavor`, `-e`, ...는 여전히 스크립트가 선언한 값을 덮어씁니다. 전체 키 목록과 병합 규칙은 [CLI 가이드](./cli#ship-the-launch-config-with-the-script)를 참조하세요.

> [!WARNING]
> 해당 테이블은 `hf` CLI에서만 읽힙니다: [run_uv_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.run_uv_job)과 [create_scheduled_uv_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.create_scheduled_uv_job)은 이를 무시하고 주어진 인수를 그대로 사용합니다. 즉, `run_uv_job("ocr.py")`와 `hf jobs uv run ocr.py`는 **동일한** Job을 실행하지 않으며, Python API에서는 `image=`, `flavor=`, ...를 명시적으로 전달해야 합니다.

#### UV 스크립트용 Docker 이미지

UV 스크립트는 인라인으로 의존성을 지정할 수 있지만, ML 워크로드에는 복잡한 의존성이 있는 경우가 많습니다. 이러한 라이브러리가 이미 설치된 사전 구축된 Docker 이미지를 사용하면 작업 시작 시간을 크게 단축하고 의존성 문제를 방지할 수 있습니다.

기본적으로 `hf jobs uv run`을 실행하면 `astral-sh/uv:python3.12-bookworm` 이미지가 사용됩니다. 이 이미지는 uv가 사전 설치된 Python 3.12 Bookworm 배포판 기반입니다.

`--image` 플래그를 사용하여 다른 이미지를 지정할 수 있습니다:

```bash
hf jobs uv run \
 --flavor a10g-large \
 --image vllm/vllm-openai:latest \
...
```

위 명령은 `vllm/vllm-openai:latest` 이미지를 사용하여 실행됩니다. 합성 데이터 생성에 vLLM을 사용하는 경우 이 접근 방식이 유용할 수 있습니다.

> [!TIP]
> 많은 추론 프레임워크가 최적화된 docker 이미지를 제공합니다. Python 생태계에서 uv의 채택이 점차 확대됨에 따라, 이러한 이미지 중에서도 uv가 사전 설치된 경우가 많아지고 있으며, 이는 hf jobs uv run을 사용할 때 정상적으로 동작한다는 것을 의미합니다.

### 예약된 작업

HF 인프라에서 실행될 작업을 예약하고 관리합니다.

`@annually`, `@yearly`, `@monthly`, `@weekly`, `@daily`, `@hourly` 또는 CRON 스케줄 표현식(예: 매주 월요일 오전 9시를 나타내는 `"0 9 * * 1"`)을 사용하여 [create_scheduled_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.create_scheduled_job) 또는 [create_scheduled_uv_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.create_scheduled_uv_job)를 실행합니다:

```python
# Schedule a job that runs every hour
>>> from huggingface_hub import create_scheduled_job
>>> create_scheduled_job(
...     image="python:3.12",
...     command=["python",  "-c", "print('This runs every hour!')"],
...     schedule="@hourly"
... )

# Use the CRON syntax
>>> create_scheduled_job(
...     image="python:3.12",
...     command=["python",  "-c", "print('This runs every 5 minutes!')"],
...     schedule="*/5 * * * *"
... )

# Schedule with GPU
>>> create_scheduled_job(
...     image="pytorch/pytorch:2.6.0-cuda12.4-cudnn9-devel",
...     command=["python",  "-c", 'import torch; print(f"This code ran with the following GPU: {torch.cuda.get_device_name()}")'],
...     schedule="@hourly",
...     flavor="a10g-small",
... )

# Schedule a UV script
>>> from huggingface_hub import create_scheduled_uv_job
>>> create_scheduled_uv_job("my_script.py", schedule="@hourly")
```

환경 변수, 시크릿, 타임아웃 등을 전달하려면 [run_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.run_job) 및 [run_uv_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.run_uv_job)과 동일한 매개변수를 사용합니다.

[list_scheduled_jobs()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.list_scheduled_jobs), [inspect_scheduled_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.inspect_scheduled_job), [suspend_scheduled_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.suspend_scheduled_job), [resume_scheduled_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.resume_scheduled_job), [update_scheduled_job_schedule()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.update_scheduled_job_schedule), [trigger_scheduled_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.trigger_scheduled_job), [delete_scheduled_job()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.delete_scheduled_job)를 사용하여 예약된 작업을 관리합니다:

```python
# List your active scheduled jobs
>>> from huggingface_hub import list_scheduled_jobs
>>> list_scheduled_jobs()

# Only list scheduled jobs with the given labels
>>> list_scheduled_jobs(labels={"env": "prod"})

# Inspect the status of a job
>>> from huggingface_hub import inspect_scheduled_job
>>> inspect_scheduled_job(scheduled_job_id=scheduled_job_id)

# Suspend (pause) a scheduled job
>>> from huggingface_hub import suspend_scheduled_job
>>> suspend_scheduled_job(scheduled_job_id=scheduled_job_id)

# Resume a scheduled job
>>> from huggingface_hub import resume_scheduled_job
>>> resume_scheduled_job(scheduled_job_id=scheduled_job_id)

# Change future run times without recreating the scheduled job
>>> from huggingface_hub import update_scheduled_job_schedule
>>> updated = update_scheduled_job_schedule(scheduled_job_id=scheduled_job_id, schedule="0 9 * * 1")
>>> updated.schedule
'0 9 * * 1'

# Trigger a scheduled job to run right now (does not change the schedule)
>>> from huggingface_hub import trigger_scheduled_job
>>> job = trigger_scheduled_job(scheduled_job_id=scheduled_job_id)
>>> job.url

# Delete a scheduled job
>>> from huggingface_hub import delete_scheduled_job
>>> delete_scheduled_job(scheduled_job_id=scheduled_job_id)
```

### 웹훅으로 Job 트리거

Webhooks를 사용하면 특정 저장소 또는 특정 사용자/조직에 속한 모든 저장소(내 저장소뿐만 아니라 모든 저장소)의 새로운 변경 사항을 수신할 수 있습니다.

Hugging Face 저장소에서 변경 사항이 발생하면 Job을 트리거하는 웹훅을 생성하려면 [create_webhook()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.create_webhook)를 사용하세요:

```python
from huggingface_hub import create_webhook

# Example: Creating a webhook that triggers a Job
webhook = create_webhook(
    job_id=job_id,
    watched=[{"type": "user", "name": "your-username"}, {"type": "org", "name": "your-org-name"}],
    domains=["repo", "discussion"],
    secret="your-secret"
)
```

Webhook은 환경 변수 `WEBHOOK_PAYLOAD`에 webhook payload를 담아 Job을 트리거합니다. Webhook에 대한 자세한 내용은 [Webhooks 문서](./webhooks)에서 확인하세요.

