Skip to main content

Module supervisor

Module supervisor 

Source
Expand description

A supervisor loop for a daemon-pipe child (issue #295).

A PrivateChild is an engine the app started itself and talks to over the daemon pipe. The rightkit-job-queue engine supervisor needs a sidecar stdio hello frame, which a daemon service does not speak; this one watches such a child with the two rightkit-child-process trackers instead:

  • poll: every SupervisorConfig::poll_interval the loop asks whether the child has exited (try_wait, no reaping surprises: the supervisor owns the child);
  • probe: a caller-supplied closure says whether the child answers (the usual one is ping_probe: connect with the child’s own secret, verify the host, call ping). Each result is fed to a HealthTracker;
  • relaunch: an exit, an unhealthy child or a startup that never became healthy is stopped (stdin closed first, then the tree is killed after SupervisorConfig::stop_grace) and the RestartTracker decides: relaunch after its backoff, wait for demand, or give up (SupervisorEvent::Exhausted).

Decisions that are easy to get wrong, and what was chosen:

  • While a generation has never answered a probe, failures are expected (it is starting), so only HealthOutcome::StartupTimedOut acts; Unhealthy acts only after the first success.
  • The first successful probe calls RestartTracker::ready, so a child that comes up and later crashes starts again from the base backoff (per the restart policy’s own rules).
  • A failed launch (the closure returned an error) is charged to the restart budget like a crash, so a binary that cannot start is not retried at poll speed forever.
  • SupervisorHandle::restart_now on a running child counts as an exit of that generation. After the policy gave up (SupervisorState::Exhausted) it forgets the budget and starts again: an explicit user start.
  • The probe runs on the supervisor thread and may block as long as its own deadline; give it a short one (ping_probe takes the bound as an argument).
  • The child is created, probed and stopped on the supervisor thread only; the launch closure is the one thing that crosses to it.

Structs§

SupervisorConfig
How a child is watched and restarted.
SupervisorHandle
Control of a running supervisor. Dropping it stops the supervisor and its child.
SupervisorStatus
A snapshot of the supervisor, from SupervisorHandle::status.

Enums§

LockState
The app’s lock state, as input to a restart (the lock mirror itself stays the app’s: a replacement core starts locked exactly when the app says the lock blocked its data). Unknown is the state of an unlock (or lock) request that got no answer because the child died first: it starts the replacement locked, so an unanswered unlock can never restart a child unlocked.
SupervisorEvent
What happened, content-free. launch is the 1-based count of children started.
SupervisorState
What the supervisor is doing now.

Constants§

DEFAULT_POLL_INTERVAL
Default SupervisorConfig::poll_interval.
DEFAULT_STOP_GRACE
Default SupervisorConfig::stop_grace.

Functions§

ping_probe
A probe for supervise: connect to the child’s service with the child’s own secret, verify the host when expect is given, and call ping. True only for a {"pong": true} answer. timeout bounds one probe (connect, hello and the call). Use HostExpectation whenever the secret is sent: a secret goes to whatever answered at the endpoint.
supervise
Start supervising. launch makes a child (normally PrivateChild::spawn of an OwnedCommand, with the per-run suite made fresh each time if the child needs one); probe says whether the running child answers (see ping_probe); on_event hears what happens. The first child is started at once, on the supervisor thread.
supervise_adopted
Supervise a child the caller already spawned (and usually already verified: it counts as launch 1, already ready, so its first crash restarts from the base backoff). The child is transferred untouched — its stdin stays open and it is not probed before the first poll. Replacements come from launch, with the lock flag resolved as in supervise_with_lock_state.
supervise_with_lock_state
supervise for a child whose replacement must start from the app’s lock state: every launch receives locked, resolved at launch time from a restart_now_with_lock override first, then lock_state, then false. LockState::Unknown resolves to locked, so an unlock the dying child never answered cannot restart it unlocked. The lock mirror that produces the state stays the app’s input.

Type Aliases§

LockStateFn
Supplies the current LockState at each launch. Runs on the supervisor thread.
SupervisorEventFn
Callback for SupervisorEvents. Runs on the supervisor thread; keep it short.