perf(skills): sync registry entries concurrently
Use bounded ordered concurrency for /skills sync so registry downloads no longer serialize one skill at a time while preserving deterministic outcome order. Harvested from PR #3139. Co-authored-by: Hmbown <101357273+Hmbown@users.noreply.github.com> Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
This commit is contained in:
@@ -61,6 +61,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
loaded only after the workspace is trusted in user-owned config, matching the
|
||||
project-local MCP trust model while preserving the documented shell-command
|
||||
hook contract.
|
||||
- **Skill registry sync latency (#3139).** `/skills sync` now syncs registry
|
||||
entries with bounded ordered concurrency, so network latency no longer stacks
|
||||
one skill at a time while output order stays deterministic.
|
||||
- **SiliconFlow China provider config (#2893/#2895).** `siliconflow-CN`
|
||||
now reads its own `[providers.siliconflow_cn]` / `[providers.siliconflow-CN]`
|
||||
table and falls back to `[providers.siliconflow]` only for unset
|
||||
|
||||
@@ -61,6 +61,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
loaded only after the workspace is trusted in user-owned config, matching the
|
||||
project-local MCP trust model while preserving the documented shell-command
|
||||
hook contract.
|
||||
- **Skill registry sync latency (#3139).** `/skills sync` now syncs registry
|
||||
entries with bounded ordered concurrency, so network latency no longer stacks
|
||||
one skill at a time while output order stays deterministic.
|
||||
- **SiliconFlow China provider config (#2893/#2895).** `siliconflow-CN`
|
||||
now reads its own `[providers.siliconflow_cn]` / `[providers.siliconflow-CN]`
|
||||
table and falls back to `[providers.siliconflow]` only for unset
|
||||
|
||||
@@ -39,6 +39,7 @@ use std::path::{Component, Path, PathBuf};
|
||||
|
||||
use anyhow::{Context, Result, bail};
|
||||
use flate2::read::GzDecoder;
|
||||
use futures_util::stream::{self, StreamExt};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
use thiserror::Error;
|
||||
@@ -69,6 +70,7 @@ pub const DEFAULT_REGISTRY_URL: &str =
|
||||
/// Default per-skill size cap (5 MiB). Honored at unpack time so a malicious
|
||||
/// gzip bomb can't blow up RAM.
|
||||
pub const DEFAULT_MAX_SIZE_BYTES: u64 = 5 * 1024 * 1024;
|
||||
const SYNC_REGISTRY_CONCURRENCY: usize = 8;
|
||||
|
||||
/// File written under each installed skill so [`update`] / [`uninstall`] can
|
||||
/// recover the original [`InstallSource`] without re-parsing user input.
|
||||
@@ -587,12 +589,11 @@ pub async fn sync_registry(
|
||||
}
|
||||
};
|
||||
|
||||
let mut outcomes = Vec::new();
|
||||
|
||||
for (name, entry) in &doc.skills {
|
||||
let outcome = sync_one_skill(name, entry, network, cache_dir, max_size).await;
|
||||
outcomes.push(outcome);
|
||||
}
|
||||
let outcomes = stream::iter(doc.skills.iter())
|
||||
.map(|(name, entry)| sync_one_skill(name, entry, network, cache_dir, max_size))
|
||||
.buffered(SYNC_REGISTRY_CONCURRENCY)
|
||||
.collect()
|
||||
.await;
|
||||
|
||||
Ok(SyncResult::Done { outcomes })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user