mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-04-28 03:49:31 +00:00
perf: skip cloud-init for minimal-tier agents with tarballs/snapshots (#2804)
* perf: skip cloud-init for minimal-tier agents with tarballs/snapshots Ubuntu 24.04 base images already have curl + git, so minimal-tier agents (claude, opencode, zeroclaw, hermes) don't need the cloud-init package install step when using tarballs or snapshots. Adds skipCloudInit flag to CloudOrchestrator — set automatically when (tarball || snapshot) && tier === "minimal". Each cloud's waitForReady checks this flag and calls waitForSshOnly instead of waitForCloudInit. Saves ~30-60s on minimal-tier agent deploys with --fast or --beta tarball. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add --fast mode and updated beta features to README Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: remove timing table from README Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: L <6723574+louisgv@users.noreply.github.com>
This commit is contained in:
parent
66036bfac9
commit
2280550c18
9 changed files with 60 additions and 9 deletions
25
README.md
25
README.md
|
|
@ -119,18 +119,35 @@ Available steps vary by agent:
|
|||
| `telegram` | openclaw | Telegram bot (set `TELEGRAM_BOT_TOKEN` for non-interactive) |
|
||||
| `whatsapp` | openclaw | WhatsApp linking (interactive QR scan, skipped in headless) |
|
||||
|
||||
#### Beta Features
|
||||
#### Fast Mode
|
||||
|
||||
Experimental features can be enabled with `--beta <feature>`. The flag is repeatable:
|
||||
Use `--fast` for significantly faster deploys. Enables all speed optimizations:
|
||||
|
||||
```bash
|
||||
spawn claude gcp --beta tarball
|
||||
spawn claude hetzner --fast
|
||||
```
|
||||
|
||||
What `--fast` does:
|
||||
- **Parallel boot**: server creation runs concurrently with API key prompt and account checks
|
||||
- **Tarballs**: installs agents from pre-built tarballs instead of live install
|
||||
- **Skip cloud-init**: for lightweight agents (Claude, OpenCode, ZeroClaw, Hermes), skips the package install wait since the base OS already has what's needed
|
||||
- **Snapshots**: uses pre-built cloud images when available (Hetzner, DigitalOcean)
|
||||
|
||||
#### Beta Features
|
||||
|
||||
Individual optimizations can be enabled separately with `--beta <feature>`. The flag is repeatable:
|
||||
|
||||
```bash
|
||||
spawn claude gcp --beta tarball --beta parallel
|
||||
```
|
||||
|
||||
| Feature | Description |
|
||||
|---------|-------------|
|
||||
| `tarball` | Use pre-built tarball for agent install (faster, skips live install) |
|
||||
| `images` | Use pre-built DigitalOcean marketplace images (faster boot, skips cloud-init) |
|
||||
| `images` | Use pre-built cloud images/snapshots (faster boot) |
|
||||
| `parallel` | Parallelize server boot with setup prompts |
|
||||
|
||||
`--fast` enables all three.
|
||||
|
||||
### Without the CLI
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@openrouter/spawn",
|
||||
"version": "0.24.1",
|
||||
"version": "0.24.2",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"spawn": "cli.js"
|
||||
|
|
|
|||
|
|
@ -1039,6 +1039,11 @@ async function waitForSsh(maxAttempts = 36): Promise<void> {
|
|||
});
|
||||
}
|
||||
|
||||
export async function waitForSshOnly(): Promise<void> {
|
||||
await waitForSsh();
|
||||
logInfo("SSH available (skipping cloud-init)");
|
||||
}
|
||||
|
||||
export async function waitForCloudInit(maxAttempts = 60): Promise<void> {
|
||||
await waitForSsh();
|
||||
const keyOpts = getSshKeyOpts(await ensureSshKeys());
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import {
|
|||
runServer,
|
||||
uploadFile,
|
||||
waitForCloudInit,
|
||||
waitForSshOnly,
|
||||
} from "./aws";
|
||||
|
||||
async function main() {
|
||||
|
|
@ -58,7 +59,11 @@ async function main() {
|
|||
},
|
||||
getServerName,
|
||||
async waitForReady() {
|
||||
await waitForCloudInit();
|
||||
if (cloud.skipCloudInit) {
|
||||
await waitForSshOnly();
|
||||
} else {
|
||||
await waitForCloudInit();
|
||||
}
|
||||
},
|
||||
interactiveSession,
|
||||
getConnectionInfo,
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ async function main() {
|
|||
},
|
||||
getServerName,
|
||||
async waitForReady() {
|
||||
if (marketplaceImage) {
|
||||
if (marketplaceImage || cloud.skipCloudInit) {
|
||||
await waitForSshOnly();
|
||||
} else {
|
||||
await waitForCloudInit();
|
||||
|
|
|
|||
|
|
@ -899,6 +899,11 @@ async function waitForSsh(maxAttempts = 36): Promise<void> {
|
|||
});
|
||||
}
|
||||
|
||||
export async function waitForSshOnly(): Promise<void> {
|
||||
await waitForSsh();
|
||||
logInfo("SSH available (skipping cloud-init)");
|
||||
}
|
||||
|
||||
export async function waitForCloudInit(maxAttempts = 120): Promise<void> {
|
||||
await waitForSsh();
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import {
|
|||
runServer,
|
||||
uploadFile,
|
||||
waitForCloudInit,
|
||||
waitForSshOnly,
|
||||
} from "./gcp";
|
||||
|
||||
async function main() {
|
||||
|
|
@ -64,7 +65,11 @@ async function main() {
|
|||
},
|
||||
getServerName,
|
||||
async waitForReady() {
|
||||
await waitForCloudInit();
|
||||
if (cloud.skipCloudInit) {
|
||||
await waitForSshOnly();
|
||||
} else {
|
||||
await waitForCloudInit();
|
||||
}
|
||||
},
|
||||
interactiveSession,
|
||||
getConnectionInfo,
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ async function main() {
|
|||
},
|
||||
getServerName,
|
||||
async waitForReady() {
|
||||
if (snapshotId) {
|
||||
if (snapshotId || cloud.skipCloudInit) {
|
||||
await waitForSshOnly();
|
||||
} else {
|
||||
await waitForCloudInit();
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ export interface CloudOrchestrator {
|
|||
runner: CloudRunner;
|
||||
/** When true, skip tarball + agent install (e.g. booting from a pre-baked snapshot). */
|
||||
skipAgentInstall?: boolean;
|
||||
/** When true, skip cloud-init wait — just wait for SSH (e.g. minimal-tier agent with tarball). */
|
||||
skipCloudInit?: boolean;
|
||||
authenticate(): Promise<void>;
|
||||
checkAccountReady?(): Promise<void>;
|
||||
promptSize(): Promise<void>;
|
||||
|
|
@ -121,6 +123,18 @@ export async function runOrchestration(
|
|||
const fastMode = process.env.SPAWN_FAST === "1" || betaFeatures.has("parallel");
|
||||
const useTarball = fastMode || betaFeatures.has("tarball");
|
||||
|
||||
// Skip cloud-init for minimal-tier agents when using tarballs or snapshots.
|
||||
// Ubuntu 24.04 base images already have curl + git, so minimal agents (claude,
|
||||
// opencode, zeroclaw, hermes) don't need the cloud-init package install step.
|
||||
// This saves ~30-60s by just waiting for SSH instead of polling for cloud-init completion.
|
||||
if (
|
||||
cloud.cloudName !== "local" &&
|
||||
(useTarball || cloud.skipAgentInstall) &&
|
||||
(agent.cloudInitTier === "minimal" || !agent.cloudInitTier)
|
||||
) {
|
||||
cloud.skipCloudInit = true;
|
||||
}
|
||||
|
||||
// 1b. Size/bundle selection (must happen before createServer)
|
||||
await cloud.promptSize();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue