Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

### Performance

- `mops install` now runs the API compatibility check concurrently with the install instead of before it, removing a registry round trip (~110 ms) from every install. The check's outcome is unchanged — an incompatible CLI still errors and skips the toolchain install — but the error now surfaces after the packages have installed. `mops publish` deliberately keeps the check serial, since publishing writes immutable registry state.
- **Parallel package installs.** Packages now download through a bounded pool instead of one at a time, sharing a fixed request budget so the package pool and the per-package file downloads cannot multiply (a cold install of 8 root packages plus transitives measured 19.7 s → 13.2 s). Branches of the graph requesting the same package share one download. New `mops install --concurrency <n>` flag and `MOPS_CONCURRENCY` environment variable cap simultaneous registry requests; the env var covers every command that installs packages. The default derives from the CPU count (2 × cores, clamped to 4–16 — the same mechanism pnpm uses for `network-concurrency`). The undocumented heuristic that quietly capped download threads whenever `GITHUB_ENV` was set is removed: it detected a brand, not a constraint.
- Writing a downloaded package's files to disk and copying packages from the global cache into `.mops/` now run through bounded pools instead of unbounded fan-outs, so a large dependency graph can no longer exhaust file descriptors.
- **Faster CLI startup.** The agent no longer eagerly synchronises time on every invocation, which cost three `read_state` requests against the ICP ledger canister — a canister mops never otherwise talks to, on a different subnet. Clock skew still self-heals: the agent re-syncs against the mops canister and retries once when a replica rejects an expired ingress expiry.
Expand Down
25 changes: 21 additions & 4 deletions cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,10 +226,18 @@ program
process.exit(1);
}

let compatible = await checkApiCompatibility();
if (!compatible) {
return;
}
// Fired here, awaited below: the check costs a registry round trip the
// install would otherwise serialize behind, and the two share no state.
// Settled into a thunk so a rejection during the install cannot surface
// as an unhandled rejection; awaiting the thunk rethrows it where the
// serial code used to throw. `mops publish` keeps its check serial — it
// writes immutable registry state.
let compatibility = checkApiCompatibility().then(
(compatible) => () => compatible,
(err) => () => {
throw err;
},
);

let ok = await installAll({
...options,
Expand All @@ -242,6 +250,13 @@ program
process.exit(1);
}

// An incompatible CLI now completes the install before this error
// surfaces — accepted, since build/test/sources never check at all.
let compatible = (await compatibility)();
if (!compatible) {
return;
}

if (options.toolchain) {
await toolchain.installAll(options);
}
Expand Down Expand Up @@ -293,6 +308,8 @@ program
await publish(options);
return;
}
// Deliberately serial (unlike `mops install`): publishing writes
// immutable registry state, so the version gate must hold it back.
let compatible = await checkApiCompatibility();
if (compatible) {
await publish(options);
Expand Down
Loading