Skip to content

Commit 6eb8f61

Browse files
authored
Fix workflow-state command and xtrigger. (#5809)
undefined
1 parent cd10adf commit 6eb8f61

File tree

103 files changed

+2940
-1163
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+2940
-1163
lines changed

changes.d/5809.feat.d

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The workflow-state command and xtrigger are now flow-aware and take universal IDs instead of separate arguments for cycle point, task name, etc. (which are still supported, but deprecated).

changes.d/5809.fix.d

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix bug where the "cylc workflow-state" command only polled for
2+
task-specific status queries and custom outputs.

cylc/flow/cfgspec/workflow.py

Lines changed: 39 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,8 +1020,9 @@ def get_script_common_text(this: str, example: Optional[str] = None):
10201020
task has generated the outputs it was expected to.
10211021
10221022
If the task fails this check its outputs are considered
1023-
:term:`incomplete` and a warning will be raised alerting you
1024-
that something has gone wrong which requires investigation.
1023+
:term:`incomplete <output completion>` and a warning will be
1024+
raised alerting you that something has gone wrong which
1025+
requires investigation.
10251026
10261027
.. note::
10271028
@@ -1731,57 +1732,34 @@ def get_script_common_text(this: str, example: Optional[str] = None):
17311732
''')
17321733

17331734
with Conf('workflow state polling', desc=f'''
1734-
Configure automatic workflow polling tasks as described in
1735-
:ref:`WorkflowStatePolling`.
1736-
1737-
The items in this section reflect
1738-
options and defaults of the ``cylc workflow-state`` command,
1739-
except that the target workflow ID and the
1740-
``--task``, ``--cycle``, and ``--status`` options are
1741-
taken from the graph notation.
1735+
Deprecated support for automatic workflow state polling tasks
1736+
as described in :ref:`WorkflowStatePolling`. Note the Cylc 7
1737+
"user" and "host" config items are not supported.
17421738
17431739
.. versionchanged:: 8.0.0
17441740
17451741
{REPLACES}``[runtime][<namespace>]suite state polling``.
1746-
'''):
1747-
Conf('user', VDR.V_STRING, desc='''
1748-
Username of your account on the workflow host.
17491742
1750-
The polling
1751-
``cylc workflow-state`` command will be
1752-
run on the remote account.
1753-
''')
1754-
Conf('host', VDR.V_STRING, desc='''
1755-
The hostname of the target workflow.
1743+
.. deprecated:: 8.3.0
17561744
1757-
The polling
1758-
``cylc workflow-state`` command will be run there.
1759-
''')
1745+
Please use the :ref:`workflow_state xtrigger
1746+
<Built-in Workflow State Triggers>` instead.
1747+
'''):
17601748
Conf('interval', VDR.V_INTERVAL, desc='''
17611749
Polling interval.
17621750
''')
17631751
Conf('max-polls', VDR.V_INTEGER, desc='''
1764-
The maximum number of polls before timing out and entering
1765-
the "failed" state.
1752+
Maximum number of polls to attempt before the task fails.
17661753
''')
17671754
Conf('message', VDR.V_STRING, desc='''
1768-
Wait for the task in the target workflow to receive a
1769-
specified message rather than achieve a state.
1755+
Target task output (task message, not trigger name).
17701756
''')
1771-
Conf('run-dir', VDR.V_STRING, desc='''
1772-
Specify the location of the top level cylc-run directory
1773-
for the other workflow.
1774-
1775-
For your own workflows, there is no need to set this as it
1776-
is always ``~/cylc-run/``. But for other workflows,
1777-
(e.g those owned by others), or mirrored workflow databases
1778-
use this item to specify the location of the top level
1779-
cylc run directory (the database should be in a the same
1780-
place relative to this location for each workflow).
1757+
Conf('alt-cylc-run-dir', VDR.V_STRING, desc='''
1758+
The cylc-run directory location of the target workflow.
1759+
Use to poll workflows owned by other users.
17811760
''')
17821761
Conf('verbose mode', VDR.V_BOOLEAN, desc='''
1783-
Run the polling ``cylc workflow-state`` command in verbose
1784-
output mode.
1762+
Run the ``cylc workflow-state`` command in verbose mode.
17851763
''')
17861764

17871765
with Conf('environment', desc='''
@@ -1958,9 +1936,10 @@ def upg(cfg, descr):
19581936
19591937
"""
19601938
u = upgrader(cfg, descr)
1939+
19611940
u.obsolete(
1962-
'7.8.0',
1963-
['runtime', '__MANY__', 'suite state polling', 'template'])
1941+
'7.8.0', ['runtime', '__MANY__', 'suite state polling', 'template']
1942+
)
19641943
u.obsolete('7.8.1', ['cylc', 'events', 'reset timer'])
19651944
u.obsolete('7.8.1', ['cylc', 'events', 'reset inactivity timer'])
19661945
u.obsolete('8.0.0', ['cylc', 'force run mode'])
@@ -1996,6 +1975,25 @@ def upg(cfg, descr):
19961975
['cylc', 'mail', 'task event batch interval'],
19971976
silent=cylc.flow.flags.cylc7_back_compat,
19981977
)
1978+
u.deprecate(
1979+
'8.0.0',
1980+
['runtime', '__MANY__', 'suite state polling'],
1981+
['runtime', '__MANY__', 'workflow state polling'],
1982+
silent=cylc.flow.flags.cylc7_back_compat,
1983+
is_section=True,
1984+
)
1985+
u.obsolete(
1986+
'8.0.0', ['runtime', '__MANY__', 'workflow state polling', 'host'])
1987+
u.obsolete(
1988+
'8.0.0', ['runtime', '__MANY__', 'workflow state polling', 'user'])
1989+
1990+
u.deprecate(
1991+
'8.3.0',
1992+
['runtime', '__MANY__', 'workflow state polling', 'run-dir'],
1993+
['runtime', '__MANY__', 'workflow state polling', 'alt-cylc-run-dir'],
1994+
silent=cylc.flow.flags.cylc7_back_compat,
1995+
)
1996+
19991997
u.deprecate(
20001998
'8.0.0',
20011999
['cylc', 'parameters'],
@@ -2063,14 +2061,6 @@ def upg(cfg, descr):
20632061
silent=cylc.flow.flags.cylc7_back_compat,
20642062
)
20652063

2066-
u.deprecate(
2067-
'8.0.0',
2068-
['runtime', '__MANY__', 'suite state polling'],
2069-
['runtime', '__MANY__', 'workflow state polling'],
2070-
silent=cylc.flow.flags.cylc7_back_compat,
2071-
is_section=True
2072-
)
2073-
20742064
for job_setting in [
20752065
'execution polling intervals',
20762066
'execution retry delays',
@@ -2196,7 +2186,7 @@ def upgrade_graph_section(cfg: Dict[str, Any], descr: str) -> None:
21962186
keys.add(key)
21972187
if keys and not cylc.flow.flags.cylc7_back_compat:
21982188
msg = (
2199-
'deprecated graph items were automatically upgraded '
2189+
'graph items were automatically upgraded '
22002190
f'in "{descr}":\n'
22012191
f' * (8.0.0) {msg_old} -> {msg_new}'
22022192
)

cylc/flow/command_polling.py

Lines changed: 32 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import sys
1919
from time import sleep
20+
from cylc.flow import LOG
2021

2122

2223
class Poller:
@@ -25,39 +26,30 @@ class Poller:
2526

2627
@classmethod
2728
def add_to_cmd_options(cls, parser, d_interval=60, d_max_polls=10):
28-
"""Add command line options for commands that can do polling"""
29+
"""Add command line options for commands that can do polling."""
2930
parser.add_option(
3031
"--max-polls",
3132
help=r"Maximum number of polls (default: %default).",
33+
type="int",
3234
metavar="INT",
3335
action="store",
3436
dest="max_polls",
35-
default=d_max_polls)
37+
default=d_max_polls
38+
)
3639
parser.add_option(
3740
"--interval",
3841
help=r"Polling interval in seconds (default: %default).",
42+
type="int",
3943
metavar="SECS",
4044
action="store",
4145
dest="interval",
42-
default=d_interval)
46+
default=d_interval
47+
)
4348

4449
def __init__(self, condition, interval, max_polls, args):
45-
4650
self.condition = condition # e.g. "workflow stopped"
47-
48-
# check max_polls is an int
49-
try:
50-
self.max_polls = int(max_polls)
51-
except ValueError:
52-
sys.exit("max_polls must be an int")
53-
54-
# check interval is an int
55-
try:
56-
self.interval = int(interval)
57-
except ValueError:
58-
sys.exit("interval must be an integer")
59-
60-
self.n_polls = 0
51+
self.interval = interval
52+
self.max_polls = max_polls or 1 # no point in zero polls
6153
self.args = args # any extra parameters needed by check()
6254

6355
async def check(self):
@@ -66,29 +58,28 @@ async def check(self):
6658

6759
async def poll(self):
6860
"""Poll for the condition embodied by self.check().
69-
Return True if condition met, or False if polling exhausted."""
7061
71-
if self.max_polls == 0:
72-
# exit 1 as we can't know if the condition is satisfied
73-
sys.exit("WARNING: nothing to do (--max-polls=0)")
74-
elif self.max_polls == 1:
75-
sys.stdout.write("checking for '%s'" % self.condition)
76-
else:
77-
sys.stdout.write("polling for '%s'" % self.condition)
62+
Return True if condition met, or False if polling exhausted.
63+
64+
"""
65+
n_polls = 0
66+
result = False
67+
68+
while True:
69+
n_polls += 1
70+
result = await self.check()
71+
if self.max_polls != 1:
72+
sys.stderr.write(".")
73+
sys.stderr.flush()
74+
if result or n_polls >= self.max_polls:
75+
if self.max_polls != 1:
76+
sys.stderr.write("\n")
77+
sys.stderr.flush()
78+
break
79+
sleep(self.interval)
7880

79-
while self.n_polls < self.max_polls:
80-
self.n_polls += 1
81-
if await self.check():
82-
sys.stdout.write(": satisfied\n")
83-
return True
84-
if self.max_polls > 1:
85-
sys.stdout.write(".")
86-
sleep(self.interval)
87-
sys.stdout.write("\n")
88-
if self.max_polls > 1:
89-
sys.stderr.write(
90-
"ERROR: condition not satisfied after %d polls\n" %
91-
self.max_polls)
81+
if result:
82+
return True
9283
else:
93-
sys.stderr.write("ERROR: condition not satisfied\n")
94-
return False
84+
LOG.error(f"failed after {n_polls} polls")
85+
return False

0 commit comments

Comments
 (0)