A long-running external server process under a supervision tree.
For processes that are supposed to outlive a single call (redis-server, a dev proxy) but must never outlive their supervisor. The child runs in its own process group; when this GenServer terminates for any reason, including supervisor shutdown and owner crash, the shim kills the group (SIGTERM, then SIGKILL after the kill grace) and the terminate blocks until the shim confirms the group is dead. If the daemon process is killed brutally (no terminate), the port closes, the shim sees stdin EOF, and the group is killed anyway; the same path covers BEAM death.
children = [
{Forcola.Daemon,
argv: ["redis-server", "--port", "6399"],
name: MyApp.Redis}
]Unlike bounded runs, a daemon has no :timeout_ms; its bound is its
supervisor. Passing :timeout_ms raises ArgumentError.
Options
:argv- required,[binary | args]as inForcola.run/2.:name- optional GenServer registration name.:cd,:env,:merge_stderr- as inForcola.run/2.:user,:group- run the child as a different user/group, as inForcola.run/2. POSIX-only, a one-way drop, and requires a privileged shim; failures fail closed and surface as the daemon's normal spawn-error exit.:kill_grace_ms- SIGTERM-to-SIGKILL grace, default5_000.:output- where child output goes; see below. Default:logger.:log_output-Loggerlevel foroutput: :logger, default:info.:log_prefix- string prepended to each logged line, default"".:ready- optional zero-arity readiness check; see below.:ready_timeout_ms- readiness deadline, default5_000.:ready_poll_ms- readiness poll interval, default100.
Output handling
output: :logger(default) - stdout and stderr are logged line by line at the:log_outputlevel, prefixed with:log_prefix. A partial line held across frames is logged once its newline arrives (or at termination).output: fun- a 2-arity function called asfun.(:stdout | :stderr, chunk)with raw chunks, from the daemon process.output: {:send, pid}-pidreceives{Forcola.Daemon, daemon_pid, {:stdout | :stderr, chunk}}messages.
With merge_stderr: true everything arrives as :stdout.
Readiness
With ready: fun, init polls fun.() (every :ready_poll_ms) until
it returns a truthy value, so start_link and supervisor startup block
until the server accepts connections:
{Forcola.Daemon,
argv: ["redis-server", "--port", "6399"],
ready: fn -> match?({:ok, _}, :gen_tcp.connect(~c"localhost", 6399, [])) end}If the check does not pass within :ready_timeout_ms, or the child
exits first, the group is killed and start_link returns
{:error, :ready_timeout} or {:error, {:exited_before_ready, reason}}.
Without :ready, start_link returns as soon as the spawn request is
written to the shim: it succeeds without any proof that the shim or the
child is alive, and a failed spawn only surfaces later as a daemon
exit. Use :ready for any daemon whose availability matters.
Exit and restart behavior
When the child exits on its own, the daemon stops: status 0 stops
:normal, a non-zero status stops {:exit_status, n}, and death by
signal stops {:exit_signal, n}. Under restart: :permanent any of
these restarts the daemon; under :transient only the abnormal ones do.
Summary
Functions
Returns a specification to start this module under a supervisor.
Starts a daemon running opts[:argv] under the shim.
Types
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec start_link(keyword()) :: GenServer.on_start()
Starts a daemon running opts[:argv] under the shim.
See the module docs for options. Raises ArgumentError on invalid
options (missing :argv, a :timeout_ms, a bad :output shape).