Flyio rate limits
'Handle Fly.io Machines API rate limits with backoff, concurrency control,From its SKILL.md
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill flyio-rate-limitsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its file declares
Copied from the file, not written here
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
4.5 KB, ~1.0k tokens by cl100k_base, as published. Nobody here has run it
Fly.io Rate Limits
Overview
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.
Rate Limit Reference
| 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 |
Rate Limiter Implementation
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);
Retry Strategy
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");
}
Batch Processing
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;
}
Error Handling
| 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 |
Resources
Next Steps
See flyio-performance-tuning.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.