Skip to content

Commit b42a490

Browse files
authored
Add support for Rocoto <hangdependency> element (#778)
1 parent e91a655 commit b42a490

File tree

7 files changed

+70
-1
lines changed

7 files changed

+70
-1
lines changed

docs/sections/user_guide/cli/tools/rocoto/foobar-realize.out

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
<command>/bin/true</command>
1414
<jobname>foo</jobname>
1515
<join>/some/path/slurm</join>
16+
<hangdependency>
17+
<sh name="ok">/bin/false</sh>
18+
</hangdependency>
1619
</task>
1720
<task name="bar" cycledefs="default">
1821
<account>wrfruc</account>

docs/sections/user_guide/cli/tools/rocoto/foobar.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ workflow:
1616
tasks:
1717
task_foo:
1818
<<: *common
19+
hangdependency:
20+
sh_ok:
21+
command: /bin/false
1922
task_bar:
2023
<<: *common
2124
dependency: {taskdep: {attrs: {task: foo}}}

docs/sections/user_guide/yaml/rocoto.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ Let's dissect the following task example:
172172
envars:
173173
person: siri
174174
dependency:
175+
hangdependency:
175176
176177
Each task is named by its UW YAML key. Blocks under ``tasks:`` prefixed with ``task_`` will be named with what follows the prefix. In the example above the task will be named ``hello`` and will appear in the XML like this:
177178

@@ -197,7 +198,7 @@ The name of the task can be any string accepted by Rocoto as a task name (includ
197198
<value>siri</value>
198199
</envar>
199200
200-
``dependency:`` -- [Optional] Any number of dependencies accepted by Rocoto. This section is described in more detail below.
201+
``dependency:`` and ``hangdependency`` -- [Optional] Any number of dependencies accepted by Rocoto. This section is described in more detail below.
201202

202203
The other keys not specifically mentioned here follow the same conventions as described in the :rocoto:`Rocoto<>` documentation.
203204

@@ -274,6 +275,11 @@ The ``datadep_foo:`` and ``datadep_bar:`` UW YAML keys were named arbitrarily af
274275

275276
This example also demonstrates the use of Rocoto's **boolean operator tags** in the structured UW YAML, e.g., ``<or>``, ``<not>``, etc. The structure follows the tree in the Rocoto XML language in that each of the subelements of the ``<and>`` tag translates to a subtree in UW YAML. Multiple boolean operator tags can be set at the same level, just as with any other tag type, by adding a descriptive suffix starting with an underscore. In the above example, the ``and:`` key could have equivalently been named ``and_data_files:`` to achieve an identical Rocoto XML result.
276277

278+
``hangdependency:``
279+
^^^^^^^^^^^^^^^^^^^
280+
281+
A ``hangdependency:`` block supports syntax identical to a ``dependency:`` block. Rocoto will interpret the resulting ``<hangdependency>`` XML element as specifying one or more conditions that, when satisfied, indicate that the task is hung and should be killed.
282+
277283
Defining Metatasks
278284
------------------
279285

src/uwtools/resources/jsonschema/rocoto.jsonschema

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,9 @@
401401
"exclusive": {
402402
"type": "string"
403403
},
404+
"hangdependency": {
405+
"$ref": "#/$defs/dependency"
406+
},
404407
"jobname": {
405408
"$ref": "#/$defs/compoundTimeString"
406409
},

src/uwtools/rocoto.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,8 @@ def _add_task(self, e: _Element, config: dict, name_attr: str) -> None:
290290
self._add_task_envar(e, name, value)
291291
if STR.dependency in config:
292292
self._add_task_dependency(e, config[STR.dependency])
293+
if STR.hangdependency in config:
294+
self._add_task_hangdependency(e, config[STR.hangdependency])
293295

294296
def _add_task_dependency(self, e: _Element, config: dict) -> None:
295297
"""
@@ -415,6 +417,17 @@ def _add_task_envar(self, e: _Element, name: str, value: str) -> None:
415417

416418
self._add_compound_time_string(e, value, STR.value)
417419

420+
def _add_task_hangdependency(self, e: _Element, config: dict) -> None:
421+
"""
422+
Add a <hangdependency> element to the <task>.
423+
424+
:param e: The parent element to add the new element to.
425+
:param config: Configuration data for this element.
426+
"""
427+
e = SubElement(e, STR.hangdependency)
428+
for tag, subconfig in config.items():
429+
self._add_task_dependency_child(e, subconfig, tag)
430+
418431
def _add_workflow(self, config: dict) -> None:
419432
"""
420433
Create the root <workflow> element.
@@ -559,6 +572,7 @@ class STR:
559572
envar: str = "envar"
560573
envars: str = "envars"
561574
exclusive: str = "exclusive"
575+
hangdependency: str = "hangdependency"
562576
jobname: str = "jobname"
563577
join: str = "join"
564578
log: str = "log"

src/uwtools/tests/fixtures/hello_workflow.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ workflow:
2121
maxtries: 2
2222
account: "&ACCOUNT;"
2323
command: "echo account for $person is &ACCOUNT; && true"
24+
hangdependency:
25+
sh_false:
26+
command: /bin/false
2427
jobname:
2528
cyclestr:
2629
attrs:
@@ -46,3 +49,6 @@ workflow:
4649
taskdep:
4750
attrs:
4851
task: hello
52+
hangdependency:
53+
sh_false:
54+
command: /bin/false

src/uwtools/tests/test_schemas.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,6 +1946,40 @@ def test_schema_rocoto_metatask_attrs():
19461946
assert "'foo' is not of type 'integer'\n" in errors({"throttle": "foo"})
19471947

19481948

1949+
def test_schema_rocoto_task_dependency():
1950+
errors = schema_validator("rocoto", "properties", "workflow", "properties", "tasks")
1951+
config = {
1952+
"task_foo": {
1953+
"command": "/bin/true",
1954+
"dependency": {
1955+
"sh_true": {
1956+
"command": "/bin/true",
1957+
},
1958+
},
1959+
"cores": 1,
1960+
"walltime": "00:01:00",
1961+
}
1962+
}
1963+
assert not errors(config)
1964+
1965+
1966+
def test_schema_rocoto_task_hangdependency():
1967+
errors = schema_validator("rocoto", "properties", "workflow", "properties", "tasks")
1968+
config = {
1969+
"task_foo": {
1970+
"command": "/bin/true",
1971+
"hangdependency": {
1972+
"sh_false": {
1973+
"command": "/bin/false",
1974+
},
1975+
},
1976+
"cores": 1,
1977+
"walltime": "00:01:00",
1978+
}
1979+
}
1980+
assert not errors(config)
1981+
1982+
19491983
def test_schema_rocoto_workflow_cycledef():
19501984
errors = schema_validator("rocoto", "properties", "workflow", "properties", "cycledef")
19511985
# Basic spec:

0 commit comments

Comments
 (0)