1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
|
.. index::
single: Dependencies (tutorial)
single: time (tutorial)
single: date (tutorial)
single: day (tutorial)
single: cron (tutorial)
.. _tutorial-time-dependencies:
Adding a time dependency
========================
Certain :term:`tasks <task>` must run at a expected time, or at a specific time interval, or to run only on the first of the month, or on Mondays,...
For this purpose, ecFlow enables the specification of time :term:`time dependencies`. These time dependencies include: :term:`time`, :term:`day`, :term:`date`, :term:`cron` and :term:`today`.
.. important::
:term:`time`, :term:`today`, and :term:`cron` dependencies will allow the associated node
to run when the time has *expired* (i.e. the specified time has been reached).
The *expired* status of the dependency will remain until the associated node is requeued.
Time Dependencies
-----------------
.. _time:
time
~~~~
A :term:`time` dependency can be:
* **absolute**, meaning it will run at the exact specified time;
* **relative**, meaning it will run at a time specified in reference to the time the :term:`suite` begun.
:term:`Time <time>` dependencies can be repeated at regular intervals. The nodes remain in complete status once all term:`time` instances have run.
.. code-block:: shell
:caption: Examples of :code:`time`
time 23:00 # at next 23:00
time 10:00 20:00 01:00 # every hour from 10am to 8pm
time +00:01 # one minute after the begin suite
time +00:10 01:00 00:05 # 10 to 60 minutes after begin every 5 minutes
.. warning::
The last line of the example above specifies a :term:`time` which will enable the task to run every five minutes.
In case the task takes longer than five minutes to complete, the time slot is skipped and the task will run only at the next time slot.
.. _cron:
cron
~~~~
A :term:`cron` dependency differs from :term:`time` by immediately requeing a task that completes.
:term:`Cron <cron>` only works with a real time clock (not a hybrid clock).
.. code-block:: shell
:caption: Examples of :code:`cron`
cron 23:00 # every day at 23:00
cron 08:00 12:00 01:00 # every hour between 8 and 12
cron -w 0,2 11:00 # every sunday and tuesday at 11 am
cron -d 1,15 02:00 # every 1st and 15th of each month at 2 am
cron -m 1 -d 1 14:00 # every first of January at 2 pm
cron -w 5L 23:00 # run on *last* Friday(5L) of each month at 23pm
cron -d 1,L 23:00 # Run on the first and last of the month at 23pm
.. _date-or-day:
date or day
~~~~~~~~~~~
A :term:`date` dependency is always absolute (i.e. no relative dates are allowed), but wildcards specification are allowed.
.. code-block:: shell
:caption: Examples of :code:`date` and :code:`day`
date 31.12.2012 # the 31st of December 2012
date 01.*.* # every first of the month
date *.10.* # every day in October
date 1.*.2008 # every first of the month, but only in 2008
day monday # every monday
today
~~~~~
A :term:`today` is a special case of :term:`time` which, in case that time instant has already passed today, does not wait for the next time instant.
This means that, for example:
* a suite that begins at 3 pm, and has a :term:`today` dependency set to 1 pm, will be immediately allowed to execute.
* a suite that begins at 3 pm, and has a :term:`today` dependency set to 5 pm, will wait until 5 pm to be allows to execute.
Mixing time dependencies
------------------------
On the same node
~~~~~~~~~~~~~~~~
A task can have several :term:`time` and :term:`date` dependencies.
The following example enables the :term:`task` :code:`t` to run on Monday at 10 am.
.. code-block:: shell
:caption: Examples of running a task on Monday at 10 am
task t
day monday # day allows only Monday's
time 10:00 # time enables execution at 10 am
The following example enables the :term:`task` :code:`t` to run on the 1st or
the 10th of each month, if these happen to be Sunday or Wednesday, at 1 am or 4 pm.
.. code-block:: shell
:caption: Examples of running a task with combined time dependencies
task t
day sunday # day allows only Sunday's
day wednesday # day allows only Wednesday's
date 01.*.* # date allows only first of every month/year
date 10.*.* # date allows only tenth of every month/year
time 01:00 # time enables execution at 1 am
time 16:00 # time enables execution at 4 pm
.. important::
With multiple time dependencies on the **same** node, the dependencies of the same
type are **OR**'ed together, and then **AND**'ed amongst the different types.
On different nodes
~~~~~~~~~~~~~~~~~~
When time dependencies are placed at different levels of the nodes hierarchy, the results can seem surprising.
The following example enables the :term:`task` :code:`t` to run on Monday at 10 am.
.. code-block::
family f
day monday # day allows only Monday's
task t
time 10:00 # time enables execution at 10 am
While the following example enables a seemingly unexpected bebaviour, where the :term:`task` :code:`t` runs on Monday morning at 00:00 and Monday at 10 am.
.. code-block::
family f
time 10:00
task t
day monday # runs on Monday morning at 00:00 and Monday at 10 am
Assuming the previous example part of a suite with an infinite repeat loop.
Task :code:`t` runs on Monday morning at 00:00, because time dependencies on different nodes act independently of each other.
In this case, the :term:`time` attribute was set free on Sunday at 10 am, and once free it stays free until it is requeued.
This means that task :code:`t` is able to run on Monday morning, and after the task runs and is requeued it will then run again on Monday at 10 am.
Like :term:`triggers <trigger>`, :term:`date` and :term:`time` dependencies can be set for a :term:`family`.
In this case, any task in this family will only run according to these :term:`dependencies`.
.. note::
All time related dependencies(like :term:`cron`, :term:`time`, :term:`today`, :term:`date` and :term:`day`) are relative to the :term:`clock` of the :term:`suite`.
For more information, see :ref:`tutorial-dates-and-clocks`
Update Suite Definition
-----------------------
Consider the following modification to the suite definition file, which adds a new :term:`family` :code:`f2` with several :term:`time dependencies`.
.. tabs::
.. tab:: Text
.. code-block:: shell
suite test
edit ECF_INCLUDE "{{HOME}}/course" # replace '{{HOME}}' appropriately
edit ECF_HOME "{{HOME}}/course"
[... previous family f1 omitted for brevity ..]
family f2
edit SLEEP 20
task t1
time 00:30 23:30 00:30 # start(hh:mm) end(hh:mm) increment(hh:mm)
task t2
day thursday
time 13:00
task t3
date 1.*.* # Date(day,month,year) - * means every day,month,year
time 12:00 # Time is not considered until date is free
task t4
time +00:02 # + means relative to suite begin/requeue time
task t5
time 00:02 # 2 minutes past midnight
endfamily
endsuite
.. tab:: Python
.. literalinclude:: src/add-a-time-dependency.py
:language: python
:caption: $HOME/course/test.py
**What to do:**
#. Modify the suite definition to include the new family :code:`f2`, as shown above.
#. Create all the necessary :term:`task scripts <ecf script>` by copying the one from task :code:`/test/f1/t7`.
#. Replace the :term:`suite`, using:
.. tabs::
.. tab:: Text
.. code-block:: shell
ecflow_client --suspend /test
ecflow_client --replace /test test.def
.. tab:: Python
.. code-block:: shell
python3 test.py
python3 client.py
#. Use :term:`ecflow_ui` to inspect why a task is :term:`queued`, by selecting a queued task and clicking on the *Why* tab.
#. (Optional) Adjust the time attributes to make all task runs.
|