|
| 1 | +# CI Pipeline Optimization Analysis (Staging Branch) |
| 2 | + |
| 3 | +## Current Workflows on Staging |
| 4 | + |
| 5 | +The staging branch has 3 workflow files (identical to main): |
| 6 | + |
| 7 | +| Workflow | File | Trigger | ~Duration | |
| 8 | +|---|---|---|---| |
| 9 | +| **Build** | `nextjs.yml` | All PRs + push to main | **~1 min** | |
| 10 | +| **Playwright Tests** | `playwright.yml` | PRs + push to main/staging | **~10 min** (x2 shards) | |
| 11 | +| **Release image** | `release-image.yml` | Tags + main push | release-only | |
| 12 | + |
| 13 | +Additionally, **CodeQL** runs on staging pushes. |
| 14 | + |
| 15 | +## Playwright Tests — The Bottleneck |
| 16 | + |
| 17 | +This is the critical path. It runs 2 shards in parallel, each taking ~10 min. Measured from recent staging runs: |
| 18 | + |
| 19 | +| Step | Shard 1 | Shard 2 | % of total | |
| 20 | +|---|---|---|---| |
| 21 | +| **Seed test data into FalkorDB** | **223s** | **220s** | **37%** | |
| 22 | +| **Run Playwright tests** | 264s | 262s | 44% | |
| 23 | +| **Install Playwright browsers** | 48s | 51s | 8% | |
| 24 | +| Install backend deps (`pip install`) | 28s | 31s | 5% | |
| 25 | +| Build frontend | 12s | 12s | 2% | |
| 26 | +| Install frontend deps (`npm ci`) | 8s | 8s | 1% | |
| 27 | +| Container init + setup | ~15s | ~15s | 3% | |
| 28 | + |
| 29 | +**Total per shard: ~600s (10 min). Total billable: ~20 min.** |
| 30 | + |
| 31 | +## Build Workflow — Wasted Work |
| 32 | + |
| 33 | +The Build workflow (~64s total) installs backend dependencies but does nothing with them: |
| 34 | + |
| 35 | +| Step | Duration | |
| 36 | +|---|---| |
| 37 | +| Install frontend deps | 7s | |
| 38 | +| Build frontend | 14s | |
| 39 | +| Lint frontend | <1s | |
| 40 | +| **Install backend deps (`pip install`)** | **35s** | |
| 41 | + |
| 42 | +The backend install accounts for **55% of the Build workflow** and serves no purpose. |
| 43 | + |
| 44 | +--- |
| 45 | + |
| 46 | +## Optimization Recommendations |
| 47 | + |
| 48 | +### 1. Cache or pre-seed FalkorDB test data (saves **~3.5 min/shard = ~7 min total**) |
| 49 | + |
| 50 | +`seed_test_data.py` clones 2 GitHub repos (GraphRAG-SDK, Flask) and runs full source analysis every run. This is the single biggest time sink at **37% of Playwright runtime**. |
| 51 | + |
| 52 | +**Options:** |
| 53 | +- **Best**: Export the seeded graph as an RDB dump, commit it as a test fixture, and restore with `redis-cli`. Eliminates the 220s step entirely. |
| 54 | +- **Good**: Cache the cloned repos + analysis output with `actions/cache` keyed on the seed script hash + repo commit SHAs. |
| 55 | +- **Minimum**: Cache just the git clones to skip network time. |
| 56 | + |
| 57 | +### 2. Cache Playwright browsers (saves **~50s/shard = ~1.5 min total**) |
| 58 | + |
| 59 | +Browsers are installed from scratch every run (`npx playwright install --with-deps`). Add: |
| 60 | + |
| 61 | +```yaml |
| 62 | +- name: Cache Playwright browsers |
| 63 | + id: playwright-cache |
| 64 | + uses: actions/cache@v4 |
| 65 | + with: |
| 66 | + path: ~/.cache/ms-playwright |
| 67 | + key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }} |
| 68 | + |
| 69 | +- name: Install Playwright Browsers |
| 70 | + if: steps.playwright-cache.outputs.cache-hit != 'true' |
| 71 | + run: npx playwright install --with-deps chromium |
| 72 | + |
| 73 | +- name: Install Playwright system deps |
| 74 | + if: steps.playwright-cache.outputs.cache-hit == 'true' |
| 75 | + run: npx playwright install-deps chromium |
| 76 | +``` |
| 77 | +
|
| 78 | +### 3. Switch `pip install` to `uv` (saves **~15-20s/shard**) |
| 79 | + |
| 80 | +Both workflows use slow `pip install`. `uv sync` is 3-5x faster: |
| 81 | + |
| 82 | +```yaml |
| 83 | +- name: Install uv |
| 84 | + uses: astral-sh/setup-uv@v5 |
| 85 | + with: |
| 86 | + version: "latest" |
| 87 | +
|
| 88 | +- name: Install dependencies |
| 89 | + run: uv sync |
| 90 | +``` |
| 91 | + |
| 92 | +### 4. Remove unused backend install from Build workflow (saves **~35s**) |
| 93 | + |
| 94 | +`nextjs.yml` installs backend deps but runs no backend tests or lint. Either: |
| 95 | +- **Remove** the `Setup Python` and `Install backend dependencies` steps entirely |
| 96 | +- **Or** add backend unit tests / pylint to justify the install |
| 97 | + |
| 98 | +### 5. Add concurrency groups (saves **queued minutes**) |
| 99 | + |
| 100 | +The Build workflow has no concurrency group. Rapid pushes queue redundant runs: |
| 101 | + |
| 102 | +```yaml |
| 103 | +concurrency: |
| 104 | + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} |
| 105 | + cancel-in-progress: true |
| 106 | +``` |
| 107 | + |
| 108 | +The Playwright workflow also lacks a concurrency group. |
| 109 | + |
| 110 | +### 6. Add npm cache (saves **~3-5s/shard**) |
| 111 | + |
| 112 | +Neither workflow caches npm. Add to `setup-node`: |
| 113 | + |
| 114 | +```yaml |
| 115 | +- uses: actions/setup-node@v4 |
| 116 | + with: |
| 117 | + node-version: 24 |
| 118 | + cache: 'npm' |
| 119 | + cache-dependency-path: | |
| 120 | + package-lock.json |
| 121 | + app/package-lock.json |
| 122 | +``` |
| 123 | + |
| 124 | +### 7. Docker build caching for releases (saves **~2-5 min** on releases) |
| 125 | + |
| 126 | +No layer caching on the Docker build. Add: |
| 127 | + |
| 128 | +```yaml |
| 129 | +- uses: docker/build-push-action@v5 |
| 130 | + with: |
| 131 | + context: . |
| 132 | + file: ./Dockerfile |
| 133 | + push: true |
| 134 | + tags: ${{ env.TAGS }} |
| 135 | + cache-from: type=gha |
| 136 | + cache-to: type=gha,mode=max |
| 137 | +``` |
| 138 | + |
| 139 | +### 8. Deduplicate npm installs in Playwright workflow |
| 140 | + |
| 141 | +The Playwright workflow runs `npm ci` twice — once for frontend (`./app`) and once for root (Playwright). These could be consolidated or at least cached. |
| 142 | + |
| 143 | +--- |
| 144 | + |
| 145 | +## Summary |
| 146 | + |
| 147 | +| # | Optimization | Time saved | Effort | |
| 148 | +|---|---|---|---| |
| 149 | +| 1 | Cache/pre-seed FalkorDB data | **~7 min** | Medium | |
| 150 | +| 2 | Cache Playwright browsers | **~1.5 min** | Low | |
| 151 | +| 3 | Switch to `uv` from `pip` | **~40s** | Low | |
| 152 | +| 4 | Remove unused backend install from Build | **~35s** | Trivial | |
| 153 | +| 5 | Add concurrency groups | Variable | Trivial | |
| 154 | +| 6 | Add npm cache | ~10s | Trivial | |
| 155 | +| 7 | Docker layer caching | ~2-5 min (releases) | Low | |
| 156 | +| 8 | Deduplicate npm installs | ~5s | Low | |
| 157 | + |
| 158 | +**Total potential savings: ~9-10 min per CI run**, bringing Playwright from ~10 min/shard down to ~4-5 min/shard (dominated by the actual test execution). |
| 159 | + |
| 160 | +The single biggest win is **pre-seeding FalkorDB data** — it alone accounts for 37% of the Playwright workflow runtime. |
0 commit comments