Skip to content

Stop the API server even when it cannot say what it is running - #2173

Closed
MayCXC wants to merge 2 commits into
apple:mainfrom
MayCXC:system-stop-any-domain
Closed

Stop the API server even when it cannot say what it is running#2173
MayCXC wants to merge 2 commits into
apple:mainfrom
MayCXC:system-stop-any-domain

Conversation

@MayCXC

@MayCXC MayCXC commented Aug 27, 2026

Copy link
Copy Markdown

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

Closes #2166.

Two independent ways container system stop reports success while leaving the services running.

The bootout rides in the failing wait's do block. Stopping the services waits for the containers to exit first, and asks the API server which of them are still running to do it. Both the wait and the bootout of that server sat in one do block, so a server that could not answer took the bootout with it into the catch: the command reported that it failed to wait for containers, said nothing about the server, and left it running.

That is the case where stopping matters most. A server that cannot list its containers is the one process that needs to go, and the command that exists to stop it is the one that gives up. Waiting is best effort now, and the services are stopped either way. What made this hard to see is that stop reported success while every service kept running, so binaries built since were never the ones executed.

The domain a service sits in belongs to the session that registered it. register bootstraps into the domain of whoever called it, so a system started from a terminal no window server owns lands in user/<uid> and the same command from a login session lands in gui/<uid>; stop looked only in the caller's own. Deregistration now tries each domain a service of this user's could be in, the caller's own first, and reports whether any domain gave the service up, so a caller looking in the wrong place is told rather than left to assume it was heard.

Relation to #2050

#2050 addresses the same disagreement from the registration side, by making getDomainString() always answer user/<uid> so that start and stop compute the same domain from any shell. The two changes are compatible and the swallowed-bootout-failure half above is needed either way.

One thing worth checking before #2050 lands on its own: a service bootstrapped into gui/<uid> by an earlier build stays in gui/<uid>, and I do not know whether launchctl bootout user/<uid>/<label> reaches a service registered in the gui subdomain. If it does not, existing installs would need a one-time manual bootout from gui/ that neither system stop nor an upgrade performs. Searching the domains, as here, does not have that question. I could only probe the user half directly: over ssh, launchctl managername reports Background, the services are registered in and found under user/501, and gui/501 does not hold them.

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs

With the API server running, container system stop leaves no container-apiserver process and container system start brings one back. Verified from an ssh session (Background), which is the domain-mismatch case that motivated the second commit.

Integration suite: 397 passed. Unit suite: 772 passed. make fmt, make check clean.

MayCXC added 2 commits August 27, 2026 20:16
Stopping the services waits for the containers to exit first, and asks the
API server which of them are still running to do it. Both the wait and the
bootout of that server sat in one do block, so a server that could not
answer took the bootout with it into the catch: the command reported that
it failed to wait for containers, said nothing about the server, and left
it running.

That is the case where stopping matters most. A server that cannot list
its containers is the one process that needs to go, and the command that
exists to stop it is the one that gives up. Waiting is best effort now,
and the services are stopped either way.

Verified: with the API server running, stopping the system leaves no
apiserver process, and starting it brings one back.
`register` bootstraps into the domain of whoever called it, so the domain a
service sits in belongs to the session that started it. A system brought up
from a terminal that no window server owns lands in `user/<uid>`, and the
same command from a login session lands in `gui/<uid>`.

Stop derived its domain the same way, from its own session, and the note
above the sweep held that the two would agree, since a domain that had
changed would have taken XPC with it. XPC reaches across the difference: a
login session drives the containers of a system started over ssh perfectly
well, because finding a service is a matter of the Mach namespace rather
than of the domain it was bootstrapped into. So the mismatch says nothing
when it happens. `bootout` is handed a domain that holds nothing, fails with
no such process, and the failure was discarded, leaving a stop that reported
stopping every service it named while all of them kept running. The start
that followed found them alive and left them as they were, so binaries built
since were never the ones being run.

Deregistering now asks each domain this user's services could be in, its
own first, and says whether any of them gave the service up. A service that
could not be stopped is logged rather than dropped.
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.

[Bug]: container system stop reports success while leaving the API server running

2 participants