* Try to fetch workspaces that need it most urgently. * For SSH workspaces: each workspace has its own repo, so fetch each one. * For local workspaces: workspaces share a repo, so fetch once per project.
(workspaces: Map<string, FrontendWorkspaceMetadata>)
| 824 | * For local workspaces: workspaces share a repo, so fetch once per project. |
| 825 | */ |
| 826 | private tryFetchWorkspaces(workspaces: Map<string, FrontendWorkspaceMetadata>): void { |
| 827 | const representativeWorkspaces = new Map< |
| 828 | string, |
| 829 | { |
| 830 | metadata: FrontendWorkspaceMetadata; |
| 831 | secondaryRepoProjectPathsByWorkspaceId: ReadonlyMap<string, string>; |
| 832 | } |
| 833 | >(); |
| 834 | |
| 835 | // Passive fetches are skipped for devcontainer workspaces whose runtime is not |
| 836 | // already running. Stale ahead/behind metadata while stopped is intentional to |
| 837 | // preserve lazy-start. |
| 838 | for (const metadata of workspaces.values()) { |
| 839 | const fetchKey = this.getFetchKey(metadata); |
| 840 | if (representativeWorkspaces.has(fetchKey) || !this.shouldFetch(fetchKey)) { |
| 841 | continue; |
| 842 | } |
| 843 | if ( |
| 844 | !canRunPassiveRuntimeCommand( |
| 845 | metadata.runtimeConfig, |
| 846 | this.runtimeStatusStore.getStatus(metadata.id) |
| 847 | ) |
| 848 | ) { |
| 849 | // Arm a one-shot retry so the workspace gets a fetch |
| 850 | // once the runtime becomes passively runnable. |
| 851 | this.registerRuntimeEligibilityRetry(this.runtimeFetchRetryUnsubscribers, metadata, () => { |
| 852 | // Clear fetch backoff so the retry isn't suppressed. |
| 853 | const retryMetadata = this.workspaceMetadata.get(metadata.id); |
| 854 | if (retryMetadata) { |
| 855 | this.fetchCache.delete(this.getFetchKey(retryMetadata)); |
| 856 | } |
| 857 | this.refreshController.requestImmediate(); |
| 858 | }); |
| 859 | continue; |
| 860 | } |
| 861 | |
| 862 | representativeWorkspaces.set(fetchKey, { |
| 863 | metadata, |
| 864 | secondaryRepoProjectPathsByWorkspaceId: this.getSecondaryRepoProjectPathsForFetchKey( |
| 865 | fetchKey, |
| 866 | workspaces |
| 867 | ), |
| 868 | }); |
| 869 | } |
| 870 | |
| 871 | // Find the workspace that needs fetching most urgently |
| 872 | let targetFetchKey: string | null = null; |
| 873 | let targetWorkspaceId: string | null = null; |
| 874 | let targetSecondaryRepoProjectPathsByWorkspaceId: ReadonlyMap<string, string> = new Map(); |
| 875 | let oldestTime = Date.now(); |
| 876 | |
| 877 | for (const [fetchKey, representative] of representativeWorkspaces) { |
| 878 | const cache = this.fetchCache.get(fetchKey); |
| 879 | const lastFetch = cache?.lastFetch ?? 0; |
| 880 | |
| 881 | if (lastFetch < oldestTime) { |
| 882 | oldestTime = lastFetch; |
| 883 | targetFetchKey = fetchKey; |
no test coverage detected