fix(vendor): surface mid-extraction death as exit 1 in vendor-codelldb.js - #392
Merged
Conversation
…b.js Fixes #389. A stalled extract-zip promise (yauzl floating-promise design: resolves only on 'close', rejects only on 'error') left main() forever pending; the event loop drained and Node exited 0 with no failure output, bypassing every deliberate failure path. Three independent layers: - extractVsixWithWatchdog: Promise.race of extractZip against a timeout (default 120s, CODELLDB_EXTRACT_TIMEOUT_MS). The pending timer keeps the event loop alive during extraction, and a stall becomes a rejection that flows through the existing retry loop and failure summary. - process.on('exit') guard (registered only when invoked directly): exiting 0 before main() settles forces exit code 1 with a requested/completed/ unresolved-platforms diagnostic. - invokedDirectly now realpaths both sides so a symlinked invocation path cannot silently skip main(). Test hooks CODELLDB_TEST_STALL_EXTRACTION / CODELLDB_TEST_SIMULATE_DRAIN enable network-free regression coverage; new spawn-based tests pin the whole-process exit-code contract (skip=0, drain=1, summary failure=1). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…wn-test timeout Review follow-ups: extractVsixWithWatchdog takes an opts seam (extractFn/timeoutMs) so the unit tests inject a stalling extractor directly instead of routing through a production env hook — the CODELLDB_TEST_STALL_EXTRACTION variable is gone, and the import tests drop their stubEnv/re-import gymnastics. CODELLDB_TEST_SIMULATE_DRAIN stays: the premature-exit guard it exercises is registered only on direct whole-process invocation, so no import-level seam can reach it. The spawn-test child timeout drops 60s -> 10s to sit inside the unit project's 15s testTimeout (a hung child now fails on real evidence within the test's own budget). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Fixes #389.
Root cause
extract-zip@2.0.1's promise settles only on yauzl'close'/'error', and its async'entry'handler is a floating promise by construction. When the entry pump stalls, nothing remains on the event loop: Node drains and exits 0 with no failure output — bypassing the failure summary, which is the script's only failure→exit-code path. This burned a docker-publish run per occurrence until v0.24.2 moved the image build to shell vendoring; the script still runs viapostinstall/prebuildand inrelease.yml.Fix — three independent layers
extractVsixWithWatchdog):Promise.raceofextractZipagainst a timeout (default 120 s,CODELLDB_EXTRACT_TIMEOUT_MS). The pending timer keeps the event loop alive for the whole extraction window — the silent-drain mode becomes impossible during extraction — and a stall becomes a rejection that flows through the existing per-attempt catch, theCODELLDB_DOWNLOAD_RETRIESloop, and the failure summary. No new control flow.process.on('exit')listener (registered only when the script is invoked directly, so importing the module stays side-effect free) forces exit code 1 with a requested/completed/unresolved-platforms diagnostic whenever the process would exit 0 beforemain()settled. This covers any future stall mode (e.g. a hung fetch body stream), not just extraction.invokedDirectlyhardening: both sides realpath'd, so a symlinked invocation path can no longer silently skipmain()and exit 0.No inner extract-retry was added: with stalls converted to rejections, the existing outer retry loop covers the transient case, and the artifact cache is only written after successful extraction so a failure can't poison it. IS_CI soft/hard exit semantics unchanged.
Tests
New
packages/codelldb-common/tests/vendor-codelldb-script.test.ts(network-free, viaCODELLDB_TEST_STALL_EXTRACTION/CODELLDB_TEST_SIMULATE_DRAINhooks):PLATFORMSliteral is untouched — the source-text drift guard incodelldb-resolver.test.tsstays green.Verification
CODELLDB_FORCE_REBUILD=true CODELLDB_PLATFORMS=win32-x64) → exit 0, "Extracted … in Nms" duration log🤖 Generated with Claude Code