Expiring Tasks / Cycles
Cylc is often used to write workflows which monitor real-world events.
For example, this workflow will run the task foo
every day at 00:00am:
[scheduling]
initial cycle point = previous(T00)
[[graph]]
P1D = """
@wall_clock => foo
"""
Sometimes such workflows might get behind, e.g. due to failures or slow task execution. In this situation, it might be necessary to skip a few tasks in order for the workflow to catch up with the real-world time.
Cylc has a concept called expiry which allows tasks to be automatically “expired” if they are running behind schedule. The expiry can be configured as an offset from the cycle time.
See also
Example 1: Skip a whole cycle of tasks
If the workflow gets behind, skip whole cycles of tasks until it catches up.
Get a copy of this example
$ cylc get-resources examples/expiry/one
[meta]
description = """
If the workflow runs slowly and the cycle time gets behind the real
world (wallclock) time, then it will skip cycles until it catches up.
Either a cycle runs or it is skipped.
When you start this workflow, the first cycle will be at 00:00am this
morning so will immediately expire causing the workflow to move onto
tomorrow's cycle.
"""
[scheduler]
allow implicit tasks = True
[scheduling]
# start the workflow at 00:00am this morning
initial cycle point = previous(T00)
# the "start" task will "expire" if the cycle time falls behind
# the wallclock time
[[special tasks]]
clock-expire = start
[[graph]]
P1D = """
# the chain of tasks we want to run
start => a => b => c => d => housekeep
# wait for the previous cycle to either complete or expire before
# continuing onto the next cycle
housekeep[-P1D] | start[-P1D]:expired? => start
"""
Example 2: Skip the remainder of a cycle of tasks
If the workflow gets behind, skip the remainder of the tasks in the cycle, then skip whole cycles of tasks until it catches up.
Get a copy of this example
$ cylc get-resources examples/expiry/two
[meta]
description = """
If the workflow runs slowly and the cycle time gets behind the real
world (wallclock) time, then it will skip tasks until it catches up.
A cycle may be skipped part way through to allow the workflow to catch
up faster.
When this workflow starts up, the first cycle will be one minute ahead
of the wallclock time. At some point in the cycle, the wallclock time
will overtake the cycle time and the next task in the chain will
expire. The workflow will then move onto the next cycle.
"""
[scheduler]
allow implicit tasks = True
[scheduling]
# start the workflow at 00:00am this morning
initial cycle point = PT1M
# any task in the workflow will "expire" rather than run if the cycle
# time falls behind the wallclock time
[[special tasks]]
clock-expire = start, a, b, c, d, housekeep
[[graph]]
P1D = """
# the chain of tasks we want to run
start => a => b => c => d => housekeep
# start the next cycle as soon as the previous cycle has finished
# OR and task in the previous cycle has expired
housekeep[-P1D]
| start[-P1D]:expire?
| a[-P1D]:expired?
| b[-P1D]:expired?
| c[-P1D]:expired?
| d[-P1D]:expired?
| housekeep[-P1D]:expired?
=> start
"""
[runtime]
[[root]]
script = sleep 12
Example 3: Skip selected tasks in a cycle
If the workflow gets behind, turn off selected tasks to allow it to catch up more quickly.
Get a copy of this example
$ cylc get-resources examples/expiry/three
[meta]
description = """
If the workflow runs slowly and the cycle time gets behind the real
world (wallclock) time, then it will skip selected tasks until it
catches up.
In this case, the tasks "b", "c" and "d" will be skipped to help the
workflow to catch up more quickly.
When this workflow starts up, the first cycle will be at 00:00am today
so the "start" task will immediately expire. This will cause tasks
"b", "c" and "d" to be configured to "skip" rather than run.
"""
[scheduler]
allow implicit tasks = True
[scheduling]
# start the workflow at 00:00am this morning
initial cycle point = previous(T00)
final cycle point = +P0D
# the "start" task will "expire" if the cycle time falls behind
# the wallclock time
[[special tasks]]
clock-expire = start
[[graph]]
P1D = """
# the chain of tasks we want to run
start | start:expired? => a => b => c => d => housekeep
"""
[runtime]
[[start]]
# if this task expires, configure the tasks "b", "c" and "d" to
# "skip" rather than run
# Note: This task will also be "skipped" if it expires
[[[events]]]
expired handlers = cylc broadcast "%(workflow)s" -p "%(point)s" -n b -n c -n d -s "run mode = skip"