fix(server): a bad package location drops that package, not the environment#903
fix(server): a bad package location drops that package, not the environment#903mlennie wants to merge 1 commit into
Conversation
…onment A package whose location could not be mounted (a path that does not exist, a `~/` typo, an unreachable URL) aborted the entire environment: loadEnvironmentIntoDisk re-threw, addConfiguredEnvironment caught it and skipped the environment, and every healthy sibling package went down with it. Meanwhile a bad *manifest* (a mounted directory with no publisher.json, or a compile error) has always been isolated per-package. Same class of user error, opposite blast radius. Make the mount path match the manifest path: when a location fails to mount, log it and continue instead of re-throwing. The environment is still created with the packages that mounted; each package that failed to mount keeps its configured status entry, whose lazy load then records a per-package failure that getFailedPackages() surfaces in /api/v0/status loadErrors (added in the parent PR). So a bad location now behaves exactly like a bad manifest: one package dropped, siblings unaffected, and the failure named per-package rather than the whole environment vanishing while the server still reports "serving". Environment-level failures that are genuinely environment-wide (a bad connection, an unresolvable environment path) still skip the environment and report at the environment level; only per-package mount failures move to per-package. Signed-off-by: Monty Lennie <[email protected]>
|
Hey — nice fix on the blast radius. One bad Two things before merge: 1.
|
Stacks on #898 (uses its per-package
loadErrorschannel), so please review and merge this after #898.What
A package whose
locationcannot be mounted (a path that does not exist, a~/typo, an unreachable URL) used to abort the entire environment:loadEnvironmentIntoDiskre-threw,addConfiguredEnvironmentcaught it and skipped the whole environment, and every healthy sibling package went down with it, while the server still reportedserving. A bad manifest (a mounted directory with nopublisher.json, or a compile error) has always been isolated to just that one package. Same class of config mistake, opposite blast radius.This makes the mount path match the manifest path: when a location fails to mount, log it and continue instead of re-throwing. The environment is still created with the packages that mounted, and each package that failed to mount is reported per-package in
/api/v0/statusloadErrors(the channel #898 added) rather than the whole environment vanishing.Why
It is the same principle as #890: a failure in one thing must not destroy what already works. It is also easy to hit in practice: one typo in a config path took down three healthy packages. We found it dogfooding, where a fresh clone served one of three packages while looking healthy.
The change
One behavioral change in
environment_store.ts: the per-location mountcatchno longer re-throwsPackageNotFoundError; it logs and continues the loop. No new plumbing was needed, the configured packages are seeded intopackageStatusesfrom config (not scanned from disk), so a package whose directory is absent is still enumerated and its lazy load records the per-package failure thatgetFailedPackages()surfaces.Environment-wide failures (a bad connection, an unresolvable environment path) still skip the environment and still report at the environment level; only per-package mount failures move to per-package.
Verification
Full root gate green (typecheck, lint, prettier, 1164 unit / 222 integration, 0 fail). Two existing tests that asserted the old "a missing path skips the whole environment" behavior were updated to the new behavior; the environment-level connection-failure test is unchanged and still passes. Added a test that a bad location alongside two good packages leaves both good ones serving and reports the bad one per-package. Verified live against a running server: bad location plus three good packages leaves all three serving with a per-package
loadError; a healthy config reports noloadErrors.One caveat worth knowing
Per-package
loadErrorsare collected on the first-boot path (config /--init/ empty-db fallback) and are not durable across a restart that restores from a populatedpublisher.db. This is pre-existing and symmetric with the bad-manifest case (failed packages are not persisted either way), and this change makes a restart strictly better, since the healthy siblings now survive instead of the whole environment being skipped. Flagging it only so the per-package signal's scope is clear.