eclipse-theia/theia

vsx-registry: startup floods OVSX registries with per-builtin queries when updateInstalled() races the frontend plugin sync

Open

#17,769 opened on Jul 8, 2026

View on GitHub
 (1 comment) (2 reactions) (0 assignees)TypeScript (2,478 forks)batch import
bughelp wantedperformancevsx-registry

Repository metrics

Stars
 (18,676 stars)
PR merge metrics
 (Avg merge 15d 4h) (75 merged PRs in 30d)

Description

Bug Description:

VSXExtensionsModel can flood the configured OVSX registries with one metadata query per deployed builtin at startup, without the user ever opening the Extensions view.

Mechanism:

  • The model is instantiated eagerly (VSXExtensionsContribution is a FrontendApplicationContribution), and updateInstalled() calls refresh(id, version) for every id returned by getInstalledPluginIds() — which includes all deployed builtins.
  • refresh() is supposed to skip locally-known plugins via shouldRefresh() (extension.plugin === undefined), but that guard reads HostedPluginSupport.getPlugin(), whose contributions map is only populated by syncPlugins().
  • updateInstalled() re-runs immediately on every HostedPluginWatcher.onDidDeploy event, while the re-sync that populates the map is debounced (50 ms) and needs RPC round trips. When the frontend connects while the backend is still deploying (cold start — e.g. one backend per session in a container), the guard loses the race and every builtin looks unknown.
  • Each lost race costs findLatestCompatibleExtension per builtin = 2 queries (targetPlatform + universal, OVSXApiFilterImpl) × N registries (OVSXRouterClient fans out to all entries in use). With ~60 builtins and 2 registries that is ~240 HTTP calls per page load.

Suggested fix: make the guard race-free. updateInstalled() already fetches the deployed versioned ids into this.deployed before the refresh loop, so skipping refresh(id, version) when `${id}@${version}` is in that set avoids the dependency on frontend sync timing. We applied exactly that as a downstream override and it eliminates the storm with no UI regression (installed/builtin entries render from local deployment metadata, as intended).

Steps to Reproduce:

  1. Configure --ovsx-router-config with 2 registries in use, and deploy the builtins bundle via --plugins=local-dir:... (~60 plugins).
  2. Start the backend and connect a browser page while plugin deployment is still in progress (reliably reproduces when the backend cold-starts per session).
  3. Watch outgoing traffic: ~4 /api/v2/-/query?extensionId=vscode.*&extensionVersion=...&targetPlatform=... calls per builtin (2 target platforms × 2 registries), with the Extensions view never opened.

Additional Information

  • Operating System: any (observed on Linux containers and macOS)
  • Theia Version: 1.72.3 and 1.73 (relevant code identical in both)

Contributor guide