Skip to content

Start one icons server per environment, and register it only once it answers - #6074

Open
backspace wants to merge 2 commits into
mainfrom
cs-12754-icons-route-loss
Open

Start one icons server per environment, and register it only once it answers#6074
backspace wants to merge 2 commits into
mainfrom
cs-12754-icons-route-loss

Conversation

@backspace

@backspace backspace commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

What this does

packages/realm-server/scripts/start-icons.sh is started by more than one task for the same environment: services:icons on its own, and services:realm-server, which spawns it so that dev-all (whose run-p list has no services:icons) still gets an icons server. Both register icons.<slug>.localhost through the one route file for the environment, last writer winning. In env mode the script now:

  • Stands by when icons are already served. It reads the port from an existing route file and, if that server answers a dist file, keeps probing it instead of starting another; the moment that server stops answering it starts and registers one of its own. Whichever task starts second leaves one server registered, and a stack that starts while the previous one is still shutting down gets a replacement the moment the old server goes. The probe goes to the port directly, the way Traefik reaches it, rather than through the hostname, so it depends on nothing but the server being up, not on DNS, the mkcert trust, or Traefik having finished a reload.
  • Registers only a server that answers. http-server binds after the script has moved on, and its port was found by binding it and letting it go, so the bind can fail. The route is written only once the server answers; if it exits or never answers within 30 s the script exits non-zero without a route.
  • Removes its route when its server exits, if the route still names its port, so Traefik answers 404 for a missing route rather than 502 for a dead upstream, and the next start of any icons task registers afresh instead of stepping aside for a route that only looks live.
  • Resolves the route directory once, in the shell, and hands it to the registration script, which previously re-derived it with a fallback relative to the process cwd.

mise-tasks/services/realm-server gains a comment saying why it spawns icons and how the script keeps that from doubling up.

Why

A route that names a port nothing listens on is indistinguishable, from a browser, from a missing route: Traefik answers 502 with no CORS headers, the console reports a CORS failure, and no service log records the request. The host app cannot render a card without its icon modules, so every render times out idle. The traefik-diagnostics artifact now reports such a port as NOT LISTENING; this change stops the route from being written in the first place.

Test plan

CI Host on this PR ran the real stack, where both services:icons and the realm-server's spawn start the script. In a host shard's log:

  • start:icons registered icons.ci.localhost on its port only after its http-server answered the probe file.
  • The realm-server-spawned start found that server answering and logged that it was standing by to replace it, instead of registering a second port.
  • Every icon request in the shard (731) reached the one registered server, and the shard's Traefik diagnostics show the icons route naming that port with a listener behind it.

The remaining paths were exercised against a Traefik with a test environment slug: a start whose http-server dies before answering exits 1 without writing a route; when the serving http-server exits, its script removes the route and the standby instance starts a replacement, registers its own port, and answers.

🤖 Generated with Claude Code

…answers

In an env-mode CI stack start-icons.sh ran twice for the same
environment: once as the listed services:icons task and once spawned by
services:realm-server, which starts it so that dev-all — whose run-p list
has no services:icons — still gets an icons server. Each run picked a
free port, backgrounded http-server, and wrote the environment's one
icons route file straight away, so the second run's port replaced the
first's whether or not its server ever came up. In one host shard the
second http-server never did: the route pointed at a port nothing
listened on, Traefik answered 502 for every icon without CORS headers,
the standby pages could not import an icon module, and every base render
timed out idle for the rest of the run while the first server sat unused
after wait-on's single probe.

The script now reads the port from any existing route file and steps
aside when that server answers a dist file, so whichever task starts
second leaves one server registered. It registers only after its own
http-server answers, and exits non-zero without writing a route if the
server dies or never answers, so a route can no longer name a dead
upstream. The probe goes to the port directly, as Traefik does, rather
than through the hostname, so it depends on nothing but the server being
up. When the server later exits, the script removes the route it wrote,
so Traefik answers 404 for a missing route rather than 502 for a dead
one and the next start registers afresh instead of stepping aside. The
route directory is resolved once in the shell and handed to the
registration script instead of being re-derived there.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 10, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-10T16:15:45.332082Z 91c43ca PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 91c43cae52

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/realm-server/scripts/start-icons.sh Outdated
A start that found the registered icons server answering exited, on the
strength of one probe. When a stack starts while the previous one is
still shutting down, that probe finds the old server alive; both of the
new stack's starts exit, the old server then goes away and takes its
route with it, and the new environment has no icons server for wait-on
to ever see.

The instance now stands by instead: it keeps probing the registered port
and, the moment that server stops answering, starts and registers a
server of its own. The environment therefore never ends with a route and
nothing behind it, whichever stack the answering server belonged to.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Host Test Results

    1 files      1 suites   2h 5m 45s ⏱️
4 733 tests 4 719 ✅ 14 💤 0 ❌
4 748 runs  4 734 ✅ 14 💤 0 ❌

Results for commit 13ec61a.

Realm Server Test Results

    1 files    208 suites   1h 14m 59s ⏱️
2 721 tests 2 721 ✅ 0 💤 0 ❌
2 760 runs  2 760 ✅ 0 💤 0 ❌

Results for commit 13ec61a.

@backspace
backspace requested a review from a team September 10, 2026 20:37
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.

2 participants