Explorar el Código

ci: tune consolidated runner concurrency

Tianyi Cui hace 2 meses
padre
commit
990f82b85c
Se han modificado 3 ficheros con 25 adiciones y 29 borrados
  1. 10 18
      .github/workflows/ci.yml
  2. 1 1
      package.json
  3. 14 10
      scripts/run-gates.ts

+ 10 - 18
.github/workflows/ci.yml

@@ -325,7 +325,8 @@ jobs:
     runs-on: dsh-ubuntu-24-04-96core
     name: node 24 / complete
     env:
-      DSH_COVERAGE_MAX_WORKERS: '32'
+      # Thirty-two Vitest forks intermittently crash Node's CJS lexer on this image.
+      DSH_COVERAGE_MAX_WORKERS: '16'
       DSH_ESLINT_CACHE: '1'
       DSH_ESLINT_CONCURRENCY: '32'
       DSH_GATE_CONCURRENCY: '32'
@@ -358,7 +359,7 @@ jobs:
           restore-keys: |
             ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
 
-      - name: Install, build, and prepare bubblewrap
+      - name: Install and prepare bubblewrap
         run: |
           pnpm install --frozen-lockfile &
           install_pid=$!
@@ -374,18 +375,13 @@ jobs:
           sandbox_pid=$!
           install_status=0
           wait "$install_pid" || install_status=$?
-          build_status=0
-          if (( install_status == 0 )); then
-            pnpm run build || build_status=$?
-          fi
           sandbox_status=0
           wait "$sandbox_pid" || sandbox_status=$?
           if (( install_status != 0 )); then exit "$install_status"; fi
-          if (( build_status != 0 )); then exit "$build_status"; fi
           exit "$sandbox_status"
 
       - name: Run complete unsharded primary Node CI concurrently
-        run: pnpm run check:ci:prebuilt
+        run: pnpm run check:ci:large-runner
 
   node-compat:
     if: github.event_name != 'workflow_dispatch' || inputs.suite == 'optimized-larger-runners'
@@ -628,13 +624,14 @@ jobs:
   windows-gates:
     if: github.event_name != 'workflow_dispatch' || inputs.suite == 'optimized-larger-runners'
     continue-on-error: true
-    runs-on: dsh-windows-2025-16core
+    runs-on: dsh-windows-2025-32core
     name: windows node 24 / observational
     env:
+      # Keep ESLint itself single-threaded: 16 ESLint workers took 174 seconds on
+      # this image. The outer scheduler still overlaps lint with the other gates.
       DSH_ESLINT_CACHE: '1'
-      DSH_ESLINT_CONCURRENCY: '16'
-      DSH_GATE_CONCURRENCY: '16'
-      DSH_PUBLINT_CONCURRENCY: '16'
+      DSH_GATE_CONCURRENCY: '32'
+      DSH_PUBLINT_CONCURRENCY: '32'
     steps:
       - uses: actions/checkout@v6
 
@@ -995,14 +992,9 @@ jobs:
           sandbox_pid=$!
           install_status=0
           wait "$install_pid" || install_status=$?
-          build_status=0
-          if (( install_status == 0 )); then
-            pnpm run build || build_status=$?
-          fi
           sandbox_status=0
           wait "$sandbox_pid" || sandbox_status=$?
           if (( install_status != 0 )); then exit "$install_status"; fi
-          if (( build_status != 0 )); then exit "$build_status"; fi
           exit "$sandbox_status"
 
       - name: Install (immutable)
@@ -1019,7 +1011,7 @@ jobs:
           DSH_GATE_CONCURRENCY: ${{ matrix.workers }}
           DSH_PUBLINT_CONCURRENCY: ${{ matrix.workers }}
           DSH_SNAPSHOT_MAX_CONCURRENCY: ${{ matrix.workers }}
-        run: pnpm run check:ci:prebuilt
+        run: pnpm run check:ci:large-runner
 
       - name: Run blocking Windows builds concurrently
         if: matrix.platform == 'windows'

+ 1 - 1
package.json

@@ -26,7 +26,7 @@
     "test:snapshot:record": "DSH_SNAPSHOT=record vitest run --config vitest.snapshot.config.ts --update",
     "test:snapshot:refresh": "DSH_SNAPSHOT=refresh vitest run --config vitest.snapshot.config.ts",
     "check:ci": "tsx scripts/run-gates.ts ci-primary",
-    "check:ci:prebuilt": "tsx scripts/run-gates.ts ci-primary-prebuilt",
+    "check:ci:large-runner": "tsx scripts/run-gates.ts ci-primary-large-runner",
     "check:ci:static": "tsx scripts/run-gates.ts ci-static",
     "check:ci:lint": "tsx scripts/run-gates.ts ci-lint",
     "check:ci:coverage": "tsx scripts/run-gates.ts ci-coverage",

+ 14 - 10
scripts/run-gates.ts

@@ -15,7 +15,7 @@ import { selectStaticGates } from './static-shards.ts'
 
 type Mode =
   | 'ci-primary'
-  | 'ci-primary-prebuilt'
+  | 'ci-primary-large-runner'
   | 'ci-static'
   | 'ci-lint'
   | 'ci-coverage'
@@ -88,7 +88,7 @@ if (results.some(result => result.status === 'failed' || result.status === 'skip
 function parseMode(raw: string | undefined): Mode {
   switch (raw) {
     case 'ci-primary':
-    case 'ci-primary-prebuilt':
+    case 'ci-primary-large-runner':
     case 'ci-static':
     case 'ci-lint':
     case 'ci-coverage':
@@ -102,7 +102,7 @@ function parseMode(raw: string | undefined): Mode {
       return raw
     default:
       throw new Error(
-        `run-gates: expected mode ci-primary | ci-primary-prebuilt | ci-static | ci-lint | ci-coverage | ci-snapshot | ci-artifacts | ci-windows-blocking | ci-windows-observational | node-compat | pre-push | doc-sync, got ${JSON.stringify(raw)}.`,
+        `run-gates: expected mode ci-primary | ci-primary-large-runner | ci-static | ci-lint | ci-coverage | ci-snapshot | ci-artifacts | ci-windows-blocking | ci-windows-observational | node-compat | pre-push | doc-sync, got ${JSON.stringify(raw)}.`,
       )
   }
 }
@@ -168,8 +168,8 @@ function gatesForMode(selected: Mode): Gate[] {
   switch (selected) {
     case 'ci-primary':
       return ciPrimaryGates()
-    case 'ci-primary-prebuilt':
-      return ciPrimaryPrebuiltGates()
+    case 'ci-primary-large-runner':
+      return ciPrimaryLargeRunnerGates()
     case 'ci-static':
       return ciStaticGates()
     case 'ci-lint': {
@@ -250,12 +250,16 @@ function ciPrimaryGates(): Gate[] {
   ]
 }
 
-function ciPrimaryPrebuiltGates(): Gate[] {
+function ciPrimaryLargeRunnerGates(): Gate[] {
+  // Typecheck does not consume build output, so a large runner can start both
+  // together while snapshot and artifact consumers still wait for the build.
   return ciPrimaryGates()
-    .filter(gate => gate.id !== 'build')
-    .map(gate => gate.needs?.includes('build') === true
-      ? { ...gate, needs: gate.needs.filter(id => id !== 'build') }
-      : gate)
+    .map((gate) => {
+      if (gate.id !== 'build') return gate
+      const eagerBuild = { ...gate }
+      delete eagerBuild.needs
+      return eagerBuild
+    })
 }
 
 function ciStaticGates(): Gate[] {