fix: isolate environment consumers from single-manager failures - #21
Open
StellaHuang95 wants to merge 1 commit into
Open
fix: isolate environment consumers from single-manager failures#21StellaHuang95 wants to merge 1 commit into
StellaHuang95 wants to merge 1 commit into
Conversation
Owner
Author
|
🔒 Automated review in progress — @StellaHuang95 is auto-reviewing this PR. |
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
force-pushed
the
isolate-environment-consumers
branch
from
August 23, 2026 04:56
c497bf8 to
ee1421f
Compare
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
force-pushed
the
isolate-environment-consumers
branch
from
August 23, 2026 05:44
ee1421f to
17c2e4a
Compare
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
force-pushed
the
isolate-environment-consumers
branch
from
August 23, 2026 06:21
17c2e4a to
df1778d
Compare
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
force-pushed
the
isolate-environment-consumers
branch
from
August 23, 2026 07:11
df1778d to
990305f
Compare
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
force-pushed
the
isolate-environment-consumers
branch
from
August 23, 2026 07:56
990305f to
0685de6
Compare
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
force-pushed
the
isolate-environment-consumers
branch
from
August 23, 2026 08:33
0685de6 to
8662b44
Compare
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
force-pushed
the
isolate-environment-consumers
branch
from
August 23, 2026 09:19
8662b44 to
672b645
Compare
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
force-pushed
the
isolate-environment-consumers
branch
from
August 23, 2026 18:15
672b645 to
3c368f7
Compare
The Python API's getEnvironments('all'|'global') and refreshEnvironments(undefined)
used Promise.all, so a single manager's rejection hid every other manager's completed
results. The environment picker also awaited every manager sequentially before showing,
so latency was additive and any rejection stopped the picker from opening at all.
- Add a private, type-safe collectFromManagers() helper that runs managers concurrently
via Promise.allSettled, returns successful results in original manager order, and throws
AggregateEnvironmentError only when every manager fails (an empty manager list resolves
with []). Each failure is logged inside its own async boundary as the manager settles, so a
synchronous throw or a slow/never-settling manager cannot hide the others or defer the
reporting of a failure. Because getEnvironments and refresh are uncancellable and can mutate
manager state, each operation is awaited to completion rather than timed out, so a
slow-but-valid manager is never falsely reported as failed and its results or refresh are
never dropped or detached. The public API contract documents the all-failed aggregate shape.
- Open the picker immediately with Browse/Create and load each manager behind an async
boundary after it is shown, through a small optional onDidShow controller seam on
showQuickPickWithButtons that reuses the existing accept/back/cancel/button wiring. Each
manager's results publish independently in manager order, so a synchronous throw, a
rejection, or a permanently pending manager can't block the others; the seam preserves the
active and selected item by reference across publications, and late updates no-op once the
picker is closed.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
StellaHuang95
force-pushed
the
isolate-environment-consumers
branch
from
August 23, 2026 18:19
3c368f7 to
423fd28
Compare
StellaHuang95
commented
Aug 23, 2026
StellaHuang95
commented
Aug 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Two user-visible failures where a single environment manager could break unrelated functionality:
getEnvironments('all' | 'global')andrefreshEnvironments(undefined)usedPromise.all, so one manager's rejection discarded every other manager's completed results.pickEnvironmentawaited every manager'sgetEnvironments('all')sequentially before showing the QuickPick, so opening latency was additive and any manager rejection prevented the picker from opening at all.Root cause
Both paths fanned out to managers without isolating per-manager failures:
Promise.allrejects as soon as any input rejects, and the picker's sequentialawaitloop both serialized discovery and propagated the first rejection before the UI was ever shown.Fix
collectFromManagers()runs managers concurrently withPromise.allSettled, returns the successful managers' results in original manager order, logs each failure with its manager id, and throws a minimal localAggregateEnvironmentErroronly when every manager fails. An empty manager list resolves with[]/void, and single-manager scope paths are unchanged.onDidShowcontroller seam onshowQuickPickWithButtons. The seam reuses the existing accept/back/cancel/button/hide/token wiring; controller updates no-op once the picker is accepted, dismissed, or disposed. A manager that rejects is logged and skipped without hiding the others, and sections are built in fixed manager order.Tests
pythonApi.failureIsolation.unit.test.ts): partial success with manager order, synchronous-throw isolation, total failure throwingAggregateEnvironmentErrorwith all reasons in order, empty-list success, per-manager logging,globalscope forwarding, and therefreshEnvironmentsequivalents.pickEnvironment.unit.test.ts): opens before slow managers resolve, fixed manager order regardless of completion order, one manager failing does not hide the others (and is logged), every manager failing still leaves a usable Browse/Create picker, a synchronous recommended item, an empty manager list, and late results after close are ignored.showQuickPickWithButtons.unit.test.ts): existing static callers (accept/hide/back/custom button/token) are unchanged, and theonDidShowcontroller populates items / toggles busy and no-ops after settle.