Skip to content

fix(cli): spawn managed serve in its own systemd scope - #48591

Closed
w0wl0lxd wants to merge 2 commits into
anomalyco:devfrom
w0wl0lxd:daemon-scope
Closed

w0wl0lxd wants to merge 2 commits into
anomalyco:devfrom
w0wl0lxd:daemon-scope

Conversation

@w0wl0lxd

@w0wl0lxd w0wl0lxd commented Sep 12, 2026 •

Copy link
Copy Markdown

Summary

Fixes #48588.

  • Daemon.start() spawns the managed serve with detached: true. That detaches the session but leaves the process inside the spawning client's cgroup. A client running under memory/pids limits (a systemd-run scope, container, etc.) then starves the shared server until the 2s health probe fails and it is recycled into another client's constrained cgroup — the kill/respawn loop described in the issue.
  • On Linux, when a user session bus and systemd-run are available, the serve is now spawned through systemd-run --user --scope --quiet --collect, so it lands in its own transient scope — a sibling of the client's cgroup — and --collect removes the scope when the serve exits.
  • A scoped spawn can still fail silently at exec (stale or forwarded bus socket passes the gate while the user manager rejects the scope, and detached hides the exit). In that case the registration never appears, so after the existing ~5s retry budget we fall back to the direct spawn.
  • Everywhere else (macOS, Windows, Linux without a user bus), the spawn path is unchanged.

Test plan

  • bun typecheck in packages/cli — clean
  • oxlint — no new findings
  • prettier --check — clean
  • Scoped path, end-to-end on NixOS: service start from a scope-confined client put the serve in app.slice/run-p<pid>.scope (a sibling of the client's scope), service status healthy, service stop SIGTERMed it and the scope was collected
  • Fallback path: pointed XDG_RUNTIME_DIR at a dir with a stale bus file — systemd-run failed, the registration retry elapsed, the direct spawn ran, and the server registered and stopped cleanly
  • Fallback path on a non-systemd host (unchanged code path, gated on process.platform, XDG_RUNTIME_DIR, bus socket, and systemd-run presence)

Not included here (possible follow-ups from the issue): tolerating reclaim stalls in the health probe, and ownership semantics for which client may recycle the registered server.

The managed serve is spawned detached, which frees it from the client's
lifetime but not its cgroup. A client under memory or pids limits still
starves the shared server until the health probe fails and it gets
recycled into another constrained client cgroup. On Linux, spawn through
systemd-run --user --scope when a user session bus is available so the
serve lands in its own transient scope, a sibling of the client's
cgroup, and --collect removes the scope when it exits. Other platforms
keep the direct spawn.

Fixes anomalyco#48588
@github-actions github-actions Bot added the needs:compliance This means the issue will auto-close after 2 hours. label Sep 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

A stale or forwarded user-bus socket can pass the spawn gate while the
user manager rejects the scope; detached hides the systemd-run exit, so
wait out the registration budget and retry with the direct spawn. Also
treat an empty XDG_RUNTIME_DIR as absent so the bus probe never resolves
relative to the caller's cwd.
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has been automatically closed because it was not updated to meet our contributing guidelines within the 2-hour window.

Feel free to open a new pull request that follows our guidelines.

@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Sep 12, 2026
@github-actions github-actions Bot closed this Sep 12, 2026
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.

service: managed serve stays inside the spawning client's cgroup — client memory limits starve the shared server into watchdog kill loops

1 participant