diff --git a/tools/egg-bin/bin/run.js b/tools/egg-bin/bin/run.js index efab902856..0dee615a07 100755 --- a/tools/egg-bin/bin/run.js +++ b/tools/egg-bin/bin/run.js @@ -1,5 +1,13 @@ #!/usr/bin/env node -import { execute } from '@oclif/core'; +function presetWindowsShell() { + if (process.platform !== 'win32' || process.env.SHELL) return; + + const comspec = process.env.ComSpec ?? process.env.COMSPEC; + process.env.SHELL = comspec?.split(/[\\/]/).at(-1) || 'cmd.exe'; +} + +presetWindowsShell(); +const { execute } = await import('@oclif/core'); await execute({ dir: import.meta.dirname }); diff --git a/tools/egg-bin/test/fixtures/my-egg-bin/bin/run.js b/tools/egg-bin/test/fixtures/my-egg-bin/bin/run.js index 176d2af58c..1c5c1f46c6 100644 --- a/tools/egg-bin/test/fixtures/my-egg-bin/bin/run.js +++ b/tools/egg-bin/test/fixtures/my-egg-bin/bin/run.js @@ -1,5 +1,13 @@ #!/usr/bin/env node -import { execute } from '@oclif/core'; +function presetWindowsShell() { + if (process.platform !== 'win32' || process.env.SHELL) return; + + const comspec = process.env.ComSpec ?? process.env.COMSPEC; + process.env.SHELL = comspec?.split(/[\\/]/).at(-1) || 'cmd.exe'; +} + +presetWindowsShell(); +const { execute } = await import('@oclif/core'); await execute({ dir: import.meta.url }); diff --git a/wiki/index.md b/wiki/index.md index a3f7db2f1b..0d68a57b55 100644 --- a/wiki/index.md +++ b/wiki/index.md @@ -13,6 +13,7 @@ Read this file before exploring raw sources. - [CI parallel test metrics](./workflows/ci-parallel-test-metrics.md) - How the CI test gate surfaces avg/peak concurrency + parallel-efficiency metrics for the isolate:false suite, and how to read or reproduce them. - [Docs and API Updates](./workflows/docs-and-api-updates.md) - How to handle changes that affect user-facing docs or durable project understanding. +- [Egg-bin Windows shell probe hotspot](./workflows/egg-bin-windows-shell-probe.md) - How PR #6014 diagnosed hosted-Windows egg-bin startup slowness and why the final fix only presets SHELL. ## Decisions diff --git a/wiki/log.md b/wiki/log.md index 883664b588..196608231e 100644 --- a/wiki/log.md +++ b/wiki/log.md @@ -2,6 +2,12 @@ Dates use the workspace-local Asia/Shanghai calendar date. +## [2026-06-28] workflow | record egg-bin Windows shell probe hotspot + +- sources touched: `tools/egg-bin/bin/run.js`, `tools/egg-bin/test/fixtures/my-egg-bin/bin/run.js`, PR #6014 CI logs +- pages updated: `wiki/index.md`, `wiki/log.md`, `wiki/workflows/egg-bin-windows-shell-probe.md` +- note: Recorded the PR #6014 investigation that found hosted-Windows `test-egg-bin` slowness was oclif's synchronous shell probe when spawned children lacked `SHELL`. The final code keeps only the Windows `SHELL` preset before dynamically importing `@oclif/core`; temporary timing and runner-diagnostic code was removed from the PR. Latest single Windows bin job passed in about 3m06s with `test/commands/test.test.ts` around 48.8s and `test/my-egg-bin.test.ts` around 8.5s. + ## [2026-06-28] package | snapshot bundler lazy-externalizes undici + urllib by default (PR #6011) - sources touched: `tools/egg-bundler/src/lib/prelude.ts`, `tools/egg-bundler/test/snapshot-lazy-external.test.ts`, `tools/egg-bundler/test/snapshot-lazy.realbuild.test.ts` diff --git a/wiki/workflows/egg-bin-windows-shell-probe.md b/wiki/workflows/egg-bin-windows-shell-probe.md new file mode 100644 index 0000000000..f3d194970d --- /dev/null +++ b/wiki/workflows/egg-bin-windows-shell-probe.md @@ -0,0 +1,60 @@ +--- +title: Egg-bin Windows shell probe hotspot +type: workflow +summary: How PR #6014 diagnosed hosted-Windows egg-bin startup slowness and why the final fix only presets SHELL. +source_files: + - tools/egg-bin/bin/run.js + - tools/egg-bin/test/fixtures/my-egg-bin/bin/run.js + - https://github.com/eggjs/egg/pull/6014 + - https://github.com/eggjs/egg/actions/runs/28316987317 + - https://github.com/eggjs/egg/actions/runs/28317525249 +updated_at: 2026-06-28 +status: active +--- + +## Finding + +The Windows `test-egg-bin` hotspot in PR #6014 was repeated child-process CLI +startup, not Vitest sharding, globby, or `egg-bin test` config construction. +Hosted Windows runners started spawned `egg-bin` children without `SHELL`, which +made oclif synchronously probe the parent process shell through PowerShell/CIM. +Files such as `tools/egg-bin/test/commands/test.test.ts` amplify that cost +because they spawn many child `egg-bin` processes. + +Inference: the hosted-runner slowdown looked like a long test file, but the +dominant repeated cost happened before the command's own test work. Temporary +CI-only timing showed normal `test` command globby/config work was tiny, while +pre-command oclif startup dominated. + +## Final Fix + +The final code fix is deliberately small: + +- in `tools/egg-bin/bin/run.js`, preset `process.env.SHELL` on Windows when it is + missing, deriving the shell name from `COMSPEC`/`ComSpec` or falling back to + `cmd.exe` +- do the same in `tools/egg-bin/test/fixtures/my-egg-bin/bin/run.js`, because the + custom CLI fixture has its own oclif entrypoint +- dynamically import `@oclif/core` after the preset, so oclif observes `SHELL` + before it initializes + +The diagnostic instrumentation used during the investigation was removed from +the final PR. The CI workflow stays as one Windows `test-egg-bin` leg; sharding +is not needed after the shell-probe fix. + +## Evidence + +Observed on CI while diagnosing PR #6014: + +- Before the fix, `test/commands/test.test.ts` on Windows took about 1,077s. +- After the main entrypoint preset, `test/commands/test.test.ts` dropped to about + 42-48s. +- After applying the same preset to the custom CLI fixture, `test/my-egg-bin.test.ts` + dropped from about 299s to about 7.6s. +- After removing the diagnostic code and keeping the minimal fix, the single + Windows `test-egg-bin` job passed in about 3m06s; file-level timings included + `test/commands/test.test.ts` at 48.8s, `test/my-egg-bin.test.ts` at 8.5s, and + `test/commands/cov.test.ts` at 30.0s. + +Remaining slow cases are real test/app startup work, mainly TypeScript fixture +cases around 9-10s, not repeated oclif shell probing.