Skip to content

Studio: Keep the site list from CLI events instead of asking the CLI each time - #5317

Closed
chubes4 wants to merge 1 commit into
trunkfrom
app/event-fed-sites
Closed

chubes4 wants to merge 1 commit into
trunkfrom
app/event-fed-sites

Conversation

@chubes4

@chubes4 chubes4 commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Related issues

How AI was used in this PR

Claude (via the Pi coding agent in a Roadie session) found the spawn pattern in CI logs, wrote the change and tests, and ran the local measurements below. I reviewed the design and the code.

Proposed Changes

The app ran site list --format json (a fresh CLI process each time) for every getSites()/getSite(). That covers each renderer refetch after a site event, and also each IPC handler that looks up a site. In a desktop E2E run, 252 of 362 CLI processes were site list.

The app already runs the _events stream, and each site event carries the site's full details plus running, computed the same way site list computes it. So the main process now keeps the list:

  • src/lib/site-list-cache.ts: holds the CLI's site list.
    • It is filled by one site list and kept current by applying each site event.
    • It is used only while _events runs.
    • It refetches when:
      • a CLI command exits (a command's event can reach the stream after the command exits);
      • an event can't be applied;
      • the list is older than 2 minutes, which matches the renderer's poll and covers changes no event reports, such as a daemon crash.
    • Events that arrive during a fetch are applied to its result, so a reader that heard of an event never gets a list from before it.
  • cli-events-subscriber.ts:
    • Applies each event before forwarding it to the renderer, so the renderer's refetch already sees it.
    • Goes live on the stream's first message, which comes after it listens for changes, so nothing falls in between.
    • Seeds its thumbnail state from that first read.
  • execute-command.ts: adds onCliCommandFinished, which the subscriber uses to drop the list after commands.
  • getSites(): unchanged for callers. Studio's metadata and PHP-recovery state are still merged on each read, and neither is cached.

Testing Instructions

  • npx vitest run --project studio: 274 tests pass.
    • site-list-cache.test.ts covers events, overlapping reads, events during a fetch, dropping, age, failures, and running without the stream.
    • The subscriber test covers going live and dropping the list after commands.
  • Local desktop E2E against packaged builds of this branch and its base 157fa556e (macOS arm64). CLI processes were counted with a wrapper around the bundled node:
Run Base: site list / all CLI This PR: site list / all CLI Result
Full suite 252 / 362 110 / 219 34/34 passed on both
sites + site-navigation 89 / 136 44 / 91 17/17 passed on both
  • tools/metrics site-startup test, 3 interleaved local runs each. These are local estimates; CI's Performance Test Results will be the real number.
    • siteStartup: 2318 / 2324 / 1817 ms vs base 3342 / 3325 / 2316 ms.
    • siteCreation: about the same (6436 / 6478 / 6976 vs 6967 / 6471 / 6437 ms).
  • CI Performance Test Results: siteStartup 2865 → 2385 ms (−16.8%), siteCreation 6532 → 6500 ms, editor load unchanged.

Pre-merge Checklist

  • Have you checked for TypeScript, React or other console errors?

@wpmobilebot

Copy link
Copy Markdown
Collaborator

📊 Performance Test Results

Comparing a7f0968 vs trunk

app-size

Metric trunk a7f0968 Diff Change
App Size (Mac) 940.68 MB 940.68 MB 0.00 MB ⚪ 0.0%

site-editor

Metric trunk a7f0968 Diff Change
load 1225 ms 1236 ms +11 ms ⚪ 0.0%

site-startup

Metric trunk a7f0968 Diff Change
siteCreation 6532 ms 6500 ms 32 ms ⚪ 0.0%
siteStartup 2865 ms 2385 ms 480 ms 🟢 -16.8%

Results are median values from multiple test runs.

Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff)

@youknowriad

Copy link
Copy Markdown
Contributor

I think the only cache we should have in our application is the tanstack query cache, so this was an explicit decision I made and I'd rather not revert it. That said, we can tweak the tanstack query cache's config if needed.

@chubes4
chubes4 marked this pull request as draft October 23, 2026 11:18
@chubes4

chubes4 commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

I'm interested in reducing latency in the CLI as this affects the entire application.

@youknowriad

Copy link
Copy Markdown
Contributor

I think it's fair, but I'd like to understand the architectural impacts and whether they're worth it. The goal is good though. So I'm interesting in knowing whether we can achieve the same gain in startup time without introducing a new cache layer (some more fragility and bugs).

@chubes4

chubes4 commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

Closing: agreed, the TanStack Query cache stays the only cache. The startup gain comes from startServer running site list to look up the site before site start; a follow-up can remove that lookup at its source instead.

@chubes4 chubes4 closed this Oct 23, 2026
@chubes4
chubes4 deleted the app/event-fed-sites branch October 23, 2026 12:48
chubes4 added a commit that referenced this pull request Oct 28, 2026
…ry site first (#5351)

## Related issues

- Follows the discussion on #5317: get the site-start gain without a new
cache layer.

## How AI was used in this PR

Claude (via the Pi coding agent in a Roadie session) traced the CLI
processes behind a site start, wrote the change, and ran the local
checks below. I reviewed the code.

## Proposed Changes

`startServer` ran `site list` (a full CLI process, about 0.35 s) to look
up the site before running `site start`. The only thing a start needs is
the site's path, and `readSite()` reads it from `cli.json` without a CLI
process. `stopServer` already looks the site up that way.

- `startServer` reads the site from `cli.json` with `readSite()`.
- A site that `cli.json` doesn't have now fails the start with "Site not
found" instead of doing nothing, which used to end in a false "Site
started" toast. The same applies when `cli.json` can't be parsed;
before, `site list` failed on that.
- It runs `getSite()` for the CLI's full site details only after a
failed start. Those details feed PHP error recovery (port, PHP version)
and the Sentry context.

There is no new state or cache: the start reads the same `cli.json` that
`site list` reads.

## Testing Instructions

- Locally (macOS arm64, packaged build), I timed every CLI process
during the `tools/metrics` site-startup test. In each of the 5 restarts,
`site start` now begins about 0.1 s after the click, with no `site list`
ahead of it. On trunk, a `site list` ran first.
- The CI Performance Test Results comment gives the `siteStartup`
number.

## Pre-merge Checklist

- [x] Have you checked for TypeScript, React or other console errors?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants