Expand description
Detached spawn of a long-lived background service (daemon, proxy, background Cockpit) so it survives the caller and holds nothing of it.
On Unix a child simply outlives its parent: stdin/stdout are null, stderr
is null or a log file, and the service leads its own process group
(process_group(0)). Without that it stays in the spawner’s group: a
terminal’s Ctrl-C reaches it, and every later CLI call from the same group
(a script, CI, an app that spawns both serve --daemon and serve --stop)
counts it among its own protected processes, so serve --status called it
not running and serve --stop could not verify it.
On Windows a child created through std::process::Command inherits two
things a background service must not keep (#2176):
- Every inheritable handle of the caller. std always passes
bInheritHandles = TRUE, so a pipe a shell gavelean-ctx restart(for example cmd’s stdout pipe incmd /c "lean-ctx restart | findstr .") stays open in the daemon and the reader never sees EOF. The spawn below usesCreateProcessWwithPROC_THREAD_ATTRIBUTE_HANDLE_LIST: the child inherits exactly its three std handles (NUL, NUL, NUL or the log file) and nothing else. - The caller’s job object. PowerShell’s
Start-Process -Waitand AI clients run their children in a job; a service left in it ends with the job or keeps-Waitwaiting (GL #545, #2176). In order:- not in a job → a plain detached spawn;
- the job allows breakaway →
CREATE_BREAKAWAY_FROM_JOB; - the job forbids it (PowerShell’s jobs do:
LimitFlags = 0) → the service is created with this user’s Explorer of this session as its parent (PROC_THREAD_ATTRIBUTE_PARENT_PROCESS), the same way a program started from the Start menu runs. Explorer is accepted only when it is%SystemRoot%\explorer.exe, runs as this user in this session and is itself in no job. The service then gets Explorer’s token: an elevated caller starts an unelevated service, which is what the service needs (same user, same data dirs); - no such Explorer (a service session, Server Core) → the service stays in the job, and one stderr line says so instead of a silent hang.
Structs§
- Detached
Child - A started background service. Dropping it neither waits for nor ends the service.
Enums§
- Detached
Stderr - Where a detached service writes its stderr; stdin and stdout are always the null device.
Functions§
- spawn_
detached - Spawn
cmdas a detached background service (see the module docs). Only the program, arguments, environment changes and working directory ofcmdare used; its stdio settings are replaced.