Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion tools/egg-bin/bin/run.js
Original file line number Diff line number Diff line change
@@ -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 });
10 changes: 9 additions & 1 deletion tools/egg-bin/test/fixtures/my-egg-bin/bin/run.js
Original file line number Diff line number Diff line change
@@ -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 });
1 change: 1 addition & 0 deletions wiki/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 6 additions & 0 deletions wiki/log.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
60 changes: 60 additions & 0 deletions wiki/workflows/egg-bin-windows-shell-probe.md
Original file line number Diff line number Diff line change
@@ -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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个差距也太大了吧。。。

- 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.
Loading