The Leitstand Job Model is a generalized model to describe arbitrary jobs as set of connected tasks forming a finite state machine. The model also provides the means to schedule a job execution to a future date and to manage running jobs.
A job is a set of tasks, that are executed in a specified order. Each task belongs exactly to one job. Each task has zero, one or more transitions to subsequent tasks. A task without outgoing transition is an terminal task. A job is done if all terminal tasks are executed. A job can be described as a finite state machine, where each state represents a task executed by the job.
A task represents a single REST API invocation. All information needed to invoke the REST API operation is conveyed in the task.
Each task has a unique ID in UUIDv4 format, a descriptive task name, a task type, and task parameters.
The task type allows to categorize tasks. All task of the same type are processed in the same way, which means that a Leitstand application can configure task processors per task type.
The task parameters convey all information needed to invoke the REST API endpoint.
A task is in one of the following task states illustrated below.
State | Description |
---|---|
READY | The task is eligible for execution provided that all preceding tasks have been completed. |
ACTIVE | The task is in progress. |
SKIPPED | The task has been skipped and will not be processed. |
CONFIRM | The task awaits to confirm the successful execution. |
COMPLETED | The task was completed successfully. |
REJECTED | The task was rejected without having been executed. |
FAILED | The task execution failed. |
TIMEOUT | The task execution exceeded a configured timeout. |
The task states SKIPPED, COMPLETED, REJECTED, SKIPPED, and FAILED are terminal states. Tasks in a terminal state have been processed.
A split task has two or more subsequent tasks. The execution flow is splitted into parallel execution flows, one per task each.
A join task has two or more preceding tasks. A join tasks gets executed when all preceding tasks have been executed successfully. The join tasks unites parallel execution flows into a single execution flow.
Jobs are modeled as finite state machines. Each task represents a state in the state machine. The state transitions define the successors of a task.
Each job has a unique job ID in UUIDv4 format, a descriptive job name, and an optional description.
The schedule date defines when the job shall be executed. The optional suspension date defines when a job must be suspended in case not all tasks have been completed by then. The auto-resume flag starts the execution of the remaining tasks at the same time on the next day.
In canary mode a job awaits to confirm the successful execution of every first task of each task type. This allows to schedule a single job for a set of devices but still to validate a task outcome on a single device before the task is executed on all remaining devices.
The job application identifies which Leitstand application created the job. The job type allows an application to differentiate between different jobs.
A job is one of the following states:
State | Description |
---|---|
NEW | A job draft that is not eligible for execution. |
READY | The job is ready for being executed. |
ACTIVE | The job is in progress. |
CONFIRM | The job awaits to confirm the successful execution of one or more tasks. |
COMPLETED | The job was completed successfully, i.e. all tasks are completed. |
FAILED | The job execution failed, i.e. at least one task failed. |
TIMEOUT | The job is timed out, i.e. at least one task exceeded a configured timeout. |
Jobs are executed in a distributed, event-driven fashion. The job scheduler does not actively wait for a task to complete, but gets notified when a task is completed as illustrated in the task execution flow sequence diagram illustrated earlier. The Leitstand job scheduler executes the first task of the job, which is called the start task. Once the start task has been completed, the successors of the start task are eligible of execution. The job scheduler proceeds executing all tasks in this way, until either no more tasks are left or the execution of a task failed.
The Job Event Loop searches for new jobs eligible for execution and executes the job start task. The remaining job tasks are processed in an event-driven fashion.
Tasks are expected to be executed asynchronously. Asynchronous execution guarantees that job scheduler threads do not actively wait for tasks being completed and prevents the thread pool from being exhausted.
The connector micro-service translates a task to the API invocation and establishes the asynchronous execution flow.
The connector accepts the REST API invocation by sending an Accepted
response, which frees the job scheduler thread right after the task has been marked as active.
Next, the connector invokes the actual REST API endpoint and sends the operation outcome to the task post-back endpoint, which was specified when the connector was called.
The task state update triggers the search for subsequent tasks eligible for execution. A task can be executed if all preceding tasks have been completed successfully.
The following scopes exist for managing job access privileges:
Scope | Description |
---|---|
job | Full job scheduler access including deletion of completed jobs and cancellation of running jobs. |
job.read | Readonly job scheduler access. |
job.task | Manage job tasks including updating the processing state of a single task. |