Adoption restarts every route of an app back-to-back: a per-app restart pace, a first-route health step, and -unit at provisioning Feature Request open
titogo runs one process per account: 74 titogo@<host>.service units on carlos-tito-ie today, with controld's runaway cap at 250. Today they sit behind proxy-only routes, and titogo's own controld restarts them after each adopt. To move them onto CARLOS-native named-unit routes (-unit, the shape the console already uses), adoption needs to restart many routes of one app without bouncing them all at once.
What adoption does today (origin/main)
- Back-to-back restarts. Each retargeted host is
try-restarted in turn, with no gap and no concurrency limit (makeRestartRoute,internal/host/agent.go).carlos restart(#113) does the same. - No health gate.
adopt.gosays "repoints have no health gate";WaitHealthyVersionexists but nothing calls it. - A safety net that only catches loud failures. A failed named-unit restart is rolled back and the host held out. But a
Type=simpleunit that starts and then dies a second later counts as a success.
For 74–250 tenants that means every one restarts within seconds. That is a burst of process starts, SQLite opens and boot-time migrations on one box, which is why titogo's controld spaces them 3s apart. On 2026-10-05 its sweep took 3m41s for 74 units, worst instance 1.9s from stop to listening.
Ask
- A per-app restart pace on adoption. For example
restart_staggerand/orrestart_concurrencyon the app or pipeline, applied when one pass retargets many routes of the same app on a box. Routes of other apps are unaffected. - Optionally, a health step for the first route. Restart one route, wait for it to report the new version (
WaitHealthyVersion) or a health probe, then continue. On failure, roll back as a failed restart does today. A build that boots and then crashes would then stop at one tenant instead of reaching all of them. - A way to stamp
unitat provisioning time.carlos instances create -unitis missing, or the console could writeprovision.unit, so a named-unit tenant route doesn't need a box-sidecarlos route -unitper host.
With (1) and (3), titogo can retire controld's fleet sweep and move tenants onto per-host live symlinks. With (2), a bad build stops at one account.
Context: titogo PRs teamtito/titogo#3872 ("restart the router first in the fleet sweep") and #3899 ("the router's CARLOS unit is assembled from the repo"), and carlos/platform#229 (CI promotes through the console).