26/Job Dependency Specification
An extension to the canonical jobspec designed to express the dependencies between one or more programs submitted to a Flux instance for execution.
Name |
github.com/flux-framework/rfc/spec_26.rst |
Editor |
Stephen Herbein <herbein1@llnl.gov> |
State |
raw |
Language
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
Goals
Define how job dependencies are represented in jobspec.
Define how job dependencies are represented as command line arguments.
Describe simple, built-in job dependency schemes.
Plan for new dependency schemes to be added later.
Describe a mechanism for specifying dependencies as a directed acyclic graph (DAG).
Describe a mechanism for specifying more advanced, runtime dependencies.
Background
RFC 21 defines a DEPEND state for jobs, which is exited once all job dependencies have been satisfied, or a fatal exception has occurred. The job must progress through DEPEND and PRIORITY states before reaching SCHED state, therefore, dependency processing is independent of the scheduler.
When a job enters DEPEND state, job manager plugins post dependency-add
events to the job eventlog, as described in RFC 21. Plugins may add
dependencies based on explicit user requests in the jobspec, or based on
other implementation-dependent criteria.
As dependencies are satisfied, job manager plugins post dependency-remove
events to the job eventlog, as described in RFC 21. The job may leave DEPEND
state once all added dependencies have been removed.
Built-in job manager plugins handle the simple dependency schemes described below. Job manager plugins may be added to handle new schemes as needed. Plugins may be self contained, or may outsource dependency processing to a service outside of the job manager; for example, a separate broker module or an entity that is not part of Flux.
Dependency Event Semantics
Dependency events SHALL only be posted to the job eventlog by job manager plugins.
Dependency events SHALL be treated as matching when their description
fields have the same value.
A dependency SHALL be considered satisfied when matching dependency-add
and dependency-remove
events have been posted.
Some special semantics for these events are needed to allow plugins to reacquire their internal state when the job manager is restarted:
Attempts to post duplicate dependency-add
events for unsatisfied
dependencies SHALL NOT raise a plugin error and SHALL NOT be posted.
Attempts to post duplicate dependency-add
events for satisfied
dependencies SHALL raise a plugin error.
Representation
A job dependency SHALL be represented as a JSON object with the following REQUIRED keys:
- scheme
(string) name of the dependency scheme
- value
(string) semantics determined by the scheme.
A dependency object MAY contain additional OPTIONAL key-value pairs, whose semantics are determined by the scheme.
in jobspec
Each dependency requested by the user SHALL be represented as an element in
the jobspec attributes.system.dependencies
array. Each element SHALL
conform to the object definition above.
If job requests no dependencies, the key attributes.system.dependencies
SHALL NOT be added to the jobspec.
on command line
On the command line, a job dependency MAY be expressed in a compact, URI-like
form, with the first OPTIONAL key-value pair represented as a URI query
string, and additional OPTIONAL key-value pairs represented as URI query
options (&
or ;
delimited):
scheme:value[?key=val[&key=val...]]
Examples:
afterany:ƒ2oLkTLb
string:foo?type=out
fluid:hungry-hippos-white-elephant
This form SHOULD be translated by the command line tool to the object form above before being shared with other parts of the system.
Simple Dependencies
The following dependency schemes are built-in.
after
value
SHALL be interpreted as the antecedent jobid, in any valid
FLUID encoding from RFC 19.
The dependency SHALL be satisfied once the antecedent job enters RUN state
and posts a start
event. If the antecedent job reaches INACTIVE state
without entering RUN state and posting a start
event, a fatal exception
SHOULD be raised on the dependent job.
afterany
value
SHALL be interpreted as the antecedent jobid, in any valid
FLUID encoding from RFC 19.
The dependency SHALL be satisfied once the antecedent job enters INACTIVE state, regardless of result.
afterok
value
SHALL be interpreted as the antecedent jobid, in any valid
FLUID encoding from RFC 19.
The dependency SHALL be satisfied once the antecedent job enters INACTIVE state, with a successful result. If the antecedent job does not conclude successfully, a fatal exception SHOULD be raised on the dependent job.
afternotok
value
SHALL be interpreted as the antecedent jobid, in any valid
FLUID encoding from RFC 19.
The dependency SHALL be satisfied once the antecedent job enters INACTIVE state, with an unsuccessful result. If the antecedent job concludes successfully, a fatal exception SHOULD be raised on the dependent job.
begin-time
value
SHALL be interpreted as a floating point timestamp in seconds
since the UNIX epoch. The dependency SHALL be satisfied once the system
time reaches the specified timestamp.
OpenMP-style Dependencies
The string
and fluid
schemes are reserved for more sophisticated
symbolic and jobid based dependencies, inspired by the OpenMP specification.
string
value
SHALL be interpreted as a symbolic dependency name.
In addition, the following keys are REQUIRED for this scheme:
- type
(string)
in
,out
, orinout
as described below.- scope
(string)
user
orglobal
as described below.
fluid
value
SHALL be interpreted as a jobid, in any valid FLUID encoding from
RFC 19.
- type
(string)
in
,out
, orinout
as described below.- scope
(string)
user
orglobal
as described below.
A dependency of this scheme
with a type
of out
SHALL be generated
automatically for every job when OpenMP-style dependencies are active.
Type
The value of the type
key SHALL be one of the following:
out This key only affects future submitted jobs. If the value of this key is the same as the value in an
in
orinout
dependency of a future job within scope, then the future job will be a dependent job of the current generated job.in If the value of this key is the same as the value in an
out
orinout
dependency of a previously submitted job within scope, then the generated job will be a dependent job of that previous job.inout If the value of this key is the same as the value in an
out
orinout
dependency of a previously submitted job within scope, then the generated job will be a dependent job of that previous job.
Planned future values for type
include inoutset
, runtime
, and all
.
Scope
The value of the scope
key SHALL be one of the following:
user All jobs previously submitted by the user are contained within this scope. A user can create a dependency of any type within this scope.
global All jobs previously submitted are contained within this scope, subject to policy constraints. The instance owner can create a dependency of any type within this scope. A non-instance owner can only create a dependency with the type
in
within this scope.
Examples
Under the description above, the following are examples of fully compliant dependency declarations.
- Example 1
Submitting a chain of jobs using
inout
Submitting multiple jobs with the following dependency definition will result in the jobs running one after another.
- type: inout
scope: user
scheme: string
value: foo
- Example 2
Submitting job that depends on a system job
Submitting a job with the following dependency will result in the job running
after the completion of the system job with the FLUID of
hungry-hippo-white-elephant
. One common use-case of this example is the case
of a large system dedicated access time (DAT). A DAT typically preempts any
running jobs. Users that do not want their jobs preempted will need to submit
their jobs with a dependency on the system DAT job.
- type: in
scope: global
scheme: fluid
value: hungry-hippo-white-elephant
- Example 3
Submitting a fan-out of jobs
A typical sub-component of a workflow DAG is a fan-out of jobs, consisting of a single pre-processing job, many tasks, and a single post-processing job. These jobs are represented as A, B, and C respectively in the DAG visualization below.
A
/|\
B B B
\|/
C
The dependency definitions for each of the job types (i.e., A, B, C) in the above DAG are provided below.
Job A |
Job(s) B |
Job C |
---|---|---|
- type: out
scope: user
scheme: string
value: A
|
- type: in
scope: user
scheme: string
value: A
- type: out
scope: user
scheme: string
value: B
|
- type: in
scope: user
scheme: string
value: B
|