Skip to content

Show where a Bloom launch spends its time, and add --no-watch - #8205

Open
JohnThomson wants to merge 2 commits into
masterfrom
launcher-startup-timing
Open

Show where a Bloom launch spends its time, and add --no-watch#8205
JohnThomson wants to merge 2 commits into
masterfrom
launcher-startup-timing

Conversation

@JohnThomson

@JohnThomson JohnThomson commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Two small improvements to the dev launcher (./go.shgo.mjswatchBloomExe.mjs), prompted by
Bloom taking so long to start that the launcher's 120s timeout was firing.

1. Show where a launch spends its time

Startup was slow and we had no idea which part was slow. The launcher now stamps each phase it
goes through (init, restore, build, waiting for Bloom to be ready) and reports how long each took,
so a slow launch tells you what was slow instead of just timing out.

Also, the launch timeout is now settable via BLOOM_LAUNCH_TIMEOUT_MS, and setting it to 0 means
"no timeout" — useful on a machine that's genuinely slow (or thrashing) where you'd rather wait than
have the launcher give up.

2. --no-watch

dotnet watch costs real time at startup (setting up file watchers over the whole C# tree) and
earns it back only occasionally, since plenty of C# changes need a restart anyway. ./go.sh --no-watch
starts Bloom with a plain dotnet run instead. It prints a warning at startup that C# changes will
need a restart, so you can't forget which mode you're in.

Measured on my machine: skipping the watch saves roughly 10s of a ~60s cold start (~17%). Not the
whole story — the bigger costs are elsewhere — but it's free, and the phase timing above is what
will let us go after the rest.

Testing

I have been running Bloom in --no-watch mode throughout a long session of front-end work
(the front-end dev server is unaffected either way), and restarting it for C# changes via the
launcher's restart control. Default behaviour (no flag) is unchanged.

Devin review


This change is Reviewable

JohnThomson and others added 2 commits August 14, 2026 12:07
Launches here kept failing with "Bloom did not emit BLOOM_AUTOMATION_READY
within 120000 ms", after which the launcher tears the whole stack down. The
message named a symptom and nothing else, so this adds the missing facts.

The launcher now logs phase timings for each launch, measured from the moment
dotnet is spawned -- which is also when the launch timeout starts, so the
phases add up to exactly the budget that timeout is policing. That matters,
because the clock was never really about "Bloom starting": it covers dotnet
watch's own startup, any restore, the MSBuild build, and only then Bloom's
initialization.

On an idle machine here, a launch reports:

    dotnet spawned                    +0.0s
    dotnet watch ready                +2.4s   (2.4s total)
    msbuild started                  +37.4s  (39.8s total)
    msbuild succeeded                +16.3s  (56.0s total)
    Bloom reported automation-ready   +2.0s  (58.0s total)

Bloom itself starts in two seconds and the build takes sixteen, but 37 seconds
-- 64% of the launch -- goes between "Hot reload enabled" and the build even
starting, and the only thing dotnet prints in that window is NuGet evaluation
warnings. That is dotnet watch working out its watch file-set by evaluating
the project. On a machine that is short of memory and paging, that is what
pushes a launch past two minutes.

Also adds BLOOM_LAUNCH_TIMEOUT_MS to override the 120s (0 waits forever), which
is what makes it possible to measure a launch without the launcher pulling the
stack down mid-build.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`./go.sh --no-watch` starts Bloom with plain `dotnet run` instead of
`dotnet watch run`. The seam was already there -- watchBloomExe.mjs had a
launchesUnderWatch constant with the not-under-watch branches already written
-- so this just makes it a real option and passes it through from go.mjs.

Measured on this machine, initial launch:

    watch (default)   58.0s, 60.5s
    --no-watch        48.9s

so about 10s, ~17%. Less than hoped: the 37s that passes under watch before
MSBuild starts is NOT all watch overhead. Plain `dotnet run` prints the same
NuGet evaluation warnings twice (a restore pass and a build pass) and takes
nearly as long to get going, so most of that window is evaluation and restore
that both modes pay for.

Where it shines is the restart: with the build already up to date, a restart in
this mode reaches automation-ready in 2.9s. Combined with not leaving a
dotnet watch and its file watchers resident, that makes it the better mode on a
machine short of memory -- which is what sent us looking, since a paging
machine was pushing launches past the two-minute timeout.

The trade-off is real and the launcher says so on startup: C# changes are not
picked up until you restart, and Bloom's restart toast never appears because
nothing is watching. Both modes were launched and verified after this change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

1 participant