plesty.server.services.launch ============================= .. py:module:: plesty.server.services.launch .. autoapi-nested-parse:: Detached process launch: no zombies, and an exit code every process can read. Several ``plesty-server`` processes look at the same servers and jobs — the CLI, the agent, ``fleet run``, the GUI. A child that its parent never reaps is a zombie: ``kill(pid, 0)`` still succeeds, so a *different* process takes it for alive and waits a full stop escalation for nothing. And a plain detached child loses its exit code for everyone but its parent. So nothing here is a direct child. :func:`launch` spawns a small waiter (``python -m plesty.server.services.launch``) that detaches itself (:func:`plesty.server.host.detach`), starts the real command with its output appended to the log, forwards the interrupt it receives, waits, and writes the exit code to *exit_file*. Callers track the waiter's pid: alive means the command runs; the exit file appears when it is over. Functions --------- .. autoapisummary:: plesty.server.services.launch.stop_file plesty.server.services.launch.launch plesty.server.services.launch.read_exit plesty.server.services.launch._wait plesty.server.services.launch._write_exit plesty.server.services.launch._report_pid plesty.server.services.launch.main Module Contents --------------- .. py:function:: stop_file(exit_file: str | os.PathLike[str]) -> pathlib.Path The file that asks the waiter of *exit_file* to stop its command. Alongside the exit file, so anything that knows where a command reports its end also knows how to ask it to end (see :func:`plesty.server.host.request_stop`). .. py:function:: launch(command: collections.abc.Sequence[str], cwd: str | os.PathLike[str], env: collections.abc.Mapping[str, str], log: str | os.PathLike[str], exit_file: str | os.PathLike[str], banner: str = '') -> int Start *command* detached; return the pid of the waiter that owns it. :param command: The command line. :param cwd: Working directory. :param env: Full environment for the command. :param log: File its stdout+stderr are appended to. :param exit_file: File the exit code is written to when it ends (removed first, so its presence means "finished"). :param banner: A line written to the log before the command starts. :raises OSError: When the waiter itself cannot be started. :raises RuntimeError: When the waiter did not report a pid. .. py:function:: read_exit(exit_file: str | os.PathLike[str]) -> int | None The exit code recorded in *exit_file*, or ``None`` while it does not exist. .. py:function:: _wait(spec: dict[str, Any]) -> int The waiter: run the command, forward the interrupt, record the exit code. .. py:function:: _write_exit(exit_file: str, code: int) -> None .. py:function:: _report_pid(pid: int) -> None .. py:function:: main() -> int Entry point of the waiter (spec as JSON on stdin). Reached as ``python -m plesty.server.services.launch`` from a source checkout and as ``plesty-server _launch`` from a bundle.