Please check the status of this specification in Launchpad before editing it. If it is Approved, contact the Assignee or another knowledgeable person before making changes.
Launchpad entry: https://launchpad.net/products/upstart/+spec/job-states
Upstart currently has a three-level state machine; goal, job state and process state. This specification proposes reducing that to a two-level state machine, combining the two lower levels into one.
The current three-level state machine is confusing, and doesn't allow as much flexibility as we would like. In particular, it's not ideal for extending the states to allow for additional scripts and actions.
- Some daemons fork off into the background, we'd like an interim state that indicates this has happened.
- Some processes don't terminate immediately, we'd like an interim state that indicates we sent the signal but haven't yet reaped it.
We'd like to introduce additional scripts, as defined in JobScripts, these need a state to be run in.
The scope of this specification is limited to modifying the current state machine, specifying where the events defined in JobEvents are emitted and when the scripts specified in JobScripts are to be run.
The easiest way to describe the proposed state machine is with a diagram (dot source):
Within this diagram, the following applies:
- Diamond nodes represent rest states.
- Oval nodes represent states during which tasks are to be performed.
- Rectangular nodes represent events to be emitted when entering the next state, they are not discreet states themselves.
- Nodes are grouped into four "virtual states" that correspond to the time between events.
Green arrows leading from a node are followed while the goal is start.
Red arrows leading from a node are followed while the goal is stop.
- State names are expected to roughly match the task being performed during that state:
- start ("exec process")
- stop ("kill process")
- The following state transitions are observed:
The starting event is emitted when entering the pre-start state.
The pre-start task is not run until the starting event has completed.
The primary process is run when entering the start state.
The post-start task is run when entering the post-start state.
The started event is emitted when entering the running state.
The pre-stop task is run when entering the pre-stop state.
The stopping event is emitted when entering the stop state.
The primary process is not killed until the stopping event has completed.
The post-stop task is run when entering the post-stop state.
The stopped event is emitted when entering the waiting state.
- Multiple state transitions in a single call will still occur; though it's no longer possible to skip past the emission of an event that can block.
A job remains in the waiting state if the goal is stop.
When a start request or event occurs, the goal is set to start:
If the job is in the waiting state, it can be moved to the starting state.
As noted by JobScripts, if the job is in the pre-stop state, it causes the pre-stop task to be terminated and the state will return to running when that task is reaped. The stopping event is never emitted.
When a stop request or event occurs, the goal is set to stop:
If the job is in the running state, it is moved to the pre-stop state.
As noted by JobScripts, if the job is in the post-start state, it causes the post-start task to be terminated and the state will change to stop when that task is reaped. The started event is never emitted.
When the primary process exits, the goal is changed to stop unless the job is marked respawn and the termination cause is listed in normalexit.
The next state, regardless of the goal, is always stop.
The pre-stop state is therefore skipped.
- A job being respawned will iterate through the usual stopping states followed by the starting states.
The implementation is largely confined to upstart/job.h, init/job.h and init/job.c.
The Job structure will lose its process_state member, and the ProcessState enum will be removed.
job_next_state and job_change_state will be amended to use the new states, other references will be adjusted.
Data preservation and migration
These changes are backwards compatible with the previous behaviour.