File size: 4,165 Bytes
9f72def
 
 
 
 
 
 
 
88e4a42
 
 
 
9f72def
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5de1095
 
 
 
 
9f72def
 
 
 
 
 
 
 
88e4a42
 
 
 
 
 
9f72def
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
---
title: GPU Capacity
emoji: πŸ›°οΈ
colorFrom: green
colorTo: red
sdk: docker
app_port: 7860
pinned: false
hf_oauth: true
hf_oauth_scopes:
  - email
hf_oauth_authorized_org: huggingface
---

# gpu-capacity

Near real-time AWS GPU on-demand capacity checker. Answers "where can I spawn a
G5 *right now*?" by probing real capacity: it creates a 1-instance targeted
On-Demand Capacity Reservation in each AZ and cancels it immediately. Success
means the capacity actually exists β€” unlike spot placement scores or instance
type offerings, which are proxies.

## Usage

```bash
AWS_PROFILE=<profile> uv run gpu-capacity
# then open http://127.0.0.1:8300
```

One representative (smallest) size per GPU family is swept automatically when
`AUTO_REFRESH_MINUTES` is set (the deployed Space uses 15); any other size can
be probed on demand from the dashboard input or the API. Results are cached in
`state.json` and shown with their age; they fade once older than
`STALE_AFTER_SECONDS` (default 900).

On the Space, `STATE_FILE` lives in the mounted HF bucket
(`rtrm/gpu-capacity-storage` on `/data`), so results survive restarts β€” and if
the restored state is fresher than the refresh period, the startup sweep is
skipped entirely.

### API

- `GET /api/availability/{instance_type}` β€” cached availability for one type
  (`?refresh=true` probes synchronously first, `?region=eu-west-1` narrows)
- `GET /api/state` β€” full cached grid (types Γ— regions, per-AZ detail)
- `POST /api/probe` β€” `{"instance_type": "g5.12xlarge", "region": "eu-west-1"}`
  (`region` optional β†’ sweeps all configured regions; any type accepted)

Reading is public. Probing (`POST /api/probe`, `refresh=true`) requires a
"Sign in with HF" session and is restricted to Hugging Face org members
(`hf_oauth_authorized_org` gates the sign-in; the backend re-checks org
membership / a verified @huggingface.co email). Sign in from the direct URL
(https://rtrm-gpu-capacity.hf.space) β€” session cookies don't work inside the
hf.co iframe.

### Config

Types and regions: `gpu_capacity/config.py`. Env vars: `AUTO_REFRESH_MINUTES`
(background sweep, default 0 = off), `STALE_AFTER_SECONDS`, `HOST`, `PORT`,
`STATE_FILE`. AWS credentials come from the default boto3 chain
(`AWS_PROFILE` locally, `AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY` secrets on
the Space).

## Cost & safety

- Reservations are billed per second at the on-demand rate; a probe lives
  ~1–3 s, so a full 8-region sweep for one type costs well under $0.01
  (except p4d/p5 which are usually not ODCR-able anyway β€” they show up as
  `unsupported`, i.e. Capacity Blocks territory).
- Only *immediate* reservations are created (no `StartDate`/
  `CommitmentDuration`), which are free to cancel at any time. Future-dated
  reservations and Capacity Blocks β€” the ones with commitments β€” go through
  different parameters/APIs and cannot be triggered accidentally.
- Every probe reservation gets `EndDate = now + 30 min` (auto-expires if the
  service dies between create and cancel), a `purpose=capacity-probe` tag, and
  a startup sweep cancels any leaked tagged reservation.

## Reading the grid

| status | meaning |
|---|---|
| `available` (n/m AZ) | reservation succeeded in n of m offered AZs |
| `no capacity` | AWS returned `InsufficientInstanceCapacity` everywhere |
| `quota` / `denied` | account quota or IAM/SCP blocks the check (not a capacity signal) |
| `n/s` | type not reservable via ODCR there (p5 β†’ Capacity Blocks) |
| `β€”` | type not offered in that region |

Note: results are account-specific (quotas, SCPs), which is what you want β€”
"can *this* account get a G5 there".

Latency: an `available` answer comes back in ~1 s per region; a `no capacity`
answer takes 10–20 s because EC2 genuinely attempts placement before returning
`InsufficientInstanceCapacity`. Probe creates run with retries disabled β€”
botocore would otherwise retry that error (HTTP 500) with backoff and multiply
the wait.

## IAM

`ec2:CreateCapacityReservation`, `ec2:CancelCapacityReservation`,
`ec2:DescribeCapacityReservations`, `ec2:DescribeInstanceTypeOfferings`,
`ec2:CreateTags` (on capacity reservations).