From flyio-pack
Rate-limits Fly.io Machines API calls using token bucket and retry with exponential backoff. Provides TypeScript implementation for concurrency and batching.
How this skill is triggered — by the user, by Claude, or both
Slash command
/flyio-pack:flyio-rate-limitsThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
The Fly.io Machines API rate-limits per organization, with write operations (create, delete, update) throttled much more aggressively than reads. Deploying fleets of edge machines across multiple regions can easily trigger 429s, especially during rolling deployments or auto-scaling events. The API returns a `Retry-After` header on rate-limited responses, and organizations running 50+ machines s...
The Fly.io Machines API rate-limits per organization, with write operations (create, delete, update) throttled much more aggressively than reads. Deploying fleets of edge machines across multiple regions can easily trigger 429s, especially during rolling deployments or auto-scaling events. The API returns a Retry-After header on rate-limited responses, and organizations running 50+ machines should implement client-side token bucket limiting to avoid cascading failures during high-churn operations.
| Endpoint | Limit | Window | Scope |
|---|---|---|---|
| Machine create/delete | 10 req | 1 minute | Per org |
| Machine start/stop | 30 req | 1 minute | Per org |
| Machine list/get | 120 req | 1 minute | Per org |
| App create/delete | 5 req | 1 minute | Per org |
| Volume operations | 15 req | 1 minute | Per org |
class FlyRateLimiter {
private tokens: number;
private lastRefill: number;
private readonly max: number;
private readonly refillRate: number;
private queue: Array<{ resolve: () => void }> = [];
constructor(maxPerMinute: number) {
this.max = maxPerMinute;
this.tokens = maxPerMinute;
this.lastRefill = Date.now();
this.refillRate = maxPerMinute / 60_000;
}
async acquire(): Promise<void> {
this.refill();
if (this.tokens >= 1) { this.tokens -= 1; return; }
return new Promise(resolve => this.queue.push({ resolve }));
}
private refill() {
const now = Date.now();
this.tokens = Math.min(this.max, this.tokens + (now - this.lastRefill) * this.refillRate);
this.lastRefill = now;
while (this.tokens >= 1 && this.queue.length) {
this.tokens -= 1;
this.queue.shift()!.resolve();
}
}
}
const writeLimiter = new FlyRateLimiter(8); // leave headroom under 10/min
const readLimiter = new FlyRateLimiter(100);
async function flyRetry<T>(fn: () => Promise<Response>, maxRetries = 4): Promise<T> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const res = await fn();
if (res.ok) return res.json();
if (res.status === 429) {
const retryAfter = parseInt(res.headers.get("Retry-After") || "10", 10);
const delay = retryAfter * 1000 + Math.random() * 2000;
await new Promise(r => setTimeout(r, delay));
continue;
}
if (res.status >= 500 && attempt < maxRetries) {
await new Promise(r => setTimeout(r, Math.pow(2, attempt) * 1000));
continue;
}
throw new Error(`Fly API ${res.status}: ${await res.text()}`);
}
throw new Error("Max retries exceeded");
}
async function rollingDeployMachines(appId: string, configs: any[], batchSize = 3) {
const results: any[] = [];
for (let i = 0; i < configs.length; i += batchSize) {
const batch = configs.slice(i, i + batchSize);
const batchResults = await Promise.all(
batch.map(async cfg => {
await writeLimiter.acquire();
return flyRetry(() =>
fetch(`https://api.machines.dev/v1/apps/${appId}/machines`, {
method: "POST", headers, body: JSON.stringify(cfg),
})
);
})
);
results.push(...batchResults);
if (i + batchSize < configs.length) await new Promise(r => setTimeout(r, 10_000));
}
return results;
}
| Issue | Cause | Fix |
|---|---|---|
| 429 on machine create | Exceeded 10 writes/min org limit | Use Retry-After header, batch deploys |
| 429 on fleet list | Monitoring polling too fast | Cache responses, poll every 30s max |
| Timeout on volume attach | Volume in another region | Verify region match before attach |
| 503 during region outage | Specific edge region down | Fail over to secondary region |
| 409 on machine update | Concurrent config change | Re-fetch machine state, retry with latest version |
See flyio-performance-tuning.
6plugins reuse this skill
First indexed Jul 10, 2026
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin flyio-packProvides typed FlyClient patterns for the Fly.io Machines REST API: machine lifecycle management, auth, error handling with retry, and multi-region orchestration.
Deploy, configure, and manage applications on the Fly.io platform using flyctl CLI, fly.toml configuration, Fly Machines, Fly Volumes, private networking, secrets, health checks, autoscaling, and GitHub Actions CI/CD. Use when deploying any application to Fly.io, writing or modifying fly.toml configuration, managing Fly Machines or Volumes, configuring networking (public services, private 6PN, Flycast, custom domains, TLS), setting secrets, configuring health checks, setting up autostop/autostart or metrics-based autoscaling, deploying with GitHub Actions, managing Fly Postgres databases, or preparing an app for production on Fly.io.
Provides quick reference for Fly.io PaaS deployments including fly.toml config, global distribution, scaling patterns, secrets management, health checks, and troubleshooting. Auto-loads on fly.toml detection.