This document describes the lifecycle of services managed by Zinit, including the various states a service can be in and how services transition between those states.
┌───────────┐
│ │
│ Unknown │
│ │
└─────┬─────┘
│
│ Monitor
▼
┌───────────┐
│ │◄────────── Dependencies
│ Blocked │ not met
│ │
└─────┬─────┘
│
│ Dependencies met
▼
┌───────────┐
Start │ │
◄──────────────────┤ Spawned │
│ │ │
│ └─────┬─────┘
│ │
│ │ Test succeeds
│ ▼
│ ┌───────────┐
│ │ │
│ │ Running ├───────────┐
│ │ │ │
│ └─────┬─────┘ │
│ │ │
│ Process exits │ Process exits │
│ (one-shot) │ (non one-shot) │ Stop/Kill
│ │ │
▼ ▼ │
┌───────────┐ ┌───────────┐ │
│ │ │ │ │
│ Success │ │ Error │◄──────────┘
│ │ │ │
└───────────┘ └───────────┘
Zinit services can exist in one of several states:
The initial state of a service when it is first monitored but before any action has been taken. This state indicates that Zinit doesn't yet have information about the service's status.
The service is waiting for its dependencies to be satisfied. A service enters this state when one or more of the services listed in its after
configuration are not yet in a Running or Success state.
The service process has been started but either:
- The test command hasn't been run yet
- The test command is still being retried
- There is no test command and Zinit is waiting to see if the process exits immediately
The service is actively running and considered healthy. A service enters this state when:
- Its test command has succeeded
- It has been running long enough to be considered stable (if no test command exists)
The service process has exited with a successful status code (0). This state is primarily meaningful for oneshot services, which are expected to exit.
The service process has exited with a non-zero status code, indicating failure. Services that aren't oneshot will be restarted after entering this state.
The service's test command has failed repeatedly, indicating that although the process is running, it isn't functioning correctly.
The service has failed to start in a way that retry won't help (e.g., command not found, permission denied). This is a terminal state until configuration is changed.
In addition to the current state, every service has a target state:
The service should be running. If it exits, Zinit will try to restart it (unless it's a oneshot service).
The service should be stopped. If it's running, Zinit will stop it and won't restart it if it exits.
- Service configuration is loaded from its YAML file
- Service enters the Unknown state
- Zinit checks if dependencies are satisfied
- If yes, the service is spawned
- If no, the service enters the Blocked state
- When a service enters Running or Success state, Zinit evaluates all services in the Blocked state
- Any Blocked services whose dependencies are now met will proceed to be spawned
- Process is spawned with the exec command
- Service enters the Spawned state
- If a test command exists:
- Zinit runs the test command repeatedly until it succeeds
- When the test succeeds, the service enters the Running state
- If no test command exists:
- For oneshot services, the service is immediately marked as Running
- For non-oneshot services, the service is marked Running once spawned
- When a service process exits, Zinit captures its exit status
- The service state is updated:
- Success state if the exit code was 0
- Error state if the exit code was non-zero
- Next steps depend on service type:
- For oneshot services, no further action is taken
- For non-oneshot services with target state Up, the service will be restarted after a delay
- For services with target state Down, no restart is attempted
- The service's target state is set to Down
- The configured stop signal (default: SIGTERM) is sent to the process
- The service remains in its current state until the process exits
- Once the process exits, it transitions to Success or Error state based on exit code
- No restart is attempted because the target state is Down
- The specified signal is sent to the process
- The service remains in its current state
- If the signal causes the process to exit:
- The service transitions to Success or Error state based on exit code
- If target state is Up, the service will be automatically restarted
- The service must already have target state Down and no running process
- The service is removed from Zinit's management
- All state information about the service is discarded
For non-oneshot services with target state Up:
- When a service exits (regardless of exit code), Zinit waits for a delay period (default: 2 seconds)
- After the delay, Zinit attempts to restart the service
- If the service fails to start, this cycle repeats indefinitely
The delay prevents rapid restart loops that could overload the system.
During system shutdown:
- All services' target states are set to Down
- Services are stopped in reverse dependency order:
- Build a reversed dependency graph
- Stop services with no dependents first
- Continue in topological order
- Each service is given time to shut down gracefully (based on shutdown_timeout)
- After all services are stopped, the system poweroff or reboot is executed