Skip to content

Commit 043b5e4

Browse files
committed
Increase default cylc clean remote timeout to 5m & allow ISO duration
1 parent 994b774 commit 043b5e4

File tree

3 files changed

+51
-10
lines changed

3 files changed

+51
-10
lines changed

cylc/flow/clean.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@
4444
Union,
4545
)
4646

47+
from metomi.isodatetime.exceptions import ISO8601SyntaxError
48+
from metomi.isodatetime.parsers import DurationParser
49+
4750
from cylc.flow import LOG
4851
from cylc.flow.cfgspec.glbl_cfg import glbl_cfg
4952
from cylc.flow.exceptions import (
@@ -187,7 +190,7 @@ def init_clean(id_: str, opts: 'Values') -> None:
187190

188191
if platform_names and platform_names != {'localhost'}:
189192
remote_clean(
190-
id_, platform_names, opts.rm_dirs, opts.remote_timeout
193+
id_, platform_names, opts.remote_timeout, opts.rm_dirs
191194
)
192195

193196
if not opts.remote_only:
@@ -338,8 +341,8 @@ def _clean_using_glob(
338341
def remote_clean(
339342
id_: str,
340343
platform_names: Iterable[str],
344+
timeout: str,
341345
rm_dirs: Optional[List[str]] = None,
342-
timeout: str = '120'
343346
) -> None:
344347
"""Run subprocesses to clean a workflow on its remote install targets
345348
(skip localhost), given a set of platform names to look up.
@@ -348,8 +351,9 @@ def remote_clean(
348351
id_: Workflow name.
349352
platform_names: List of platform names to look up in the global
350353
config, in order to determine the install targets to clean on.
354+
timeout: ISO 8601 duration or number of seconds to wait before
355+
cancelling.
351356
rm_dirs: Sub dirs to remove instead of the whole run dir.
352-
timeout: Number of seconds to wait before cancelling.
353357
"""
354358
try:
355359
install_targets_map = (
@@ -358,6 +362,10 @@ def remote_clean(
358362
raise PlatformLookupError(
359363
f"Cannot clean {id_} on remote platforms as the workflow database "
360364
f"is out of date/inconsistent with the global config - {exc}")
365+
366+
with suppress(ISO8601SyntaxError):
367+
timeout = str(DurationParser().parse(timeout).get_seconds())
368+
361369
queue: Deque[RemoteCleanQueueTuple] = deque()
362370
remote_clean_cmd = partial(
363371
_remote_clean_cmd, id_=id_, rm_dirs=rm_dirs, timeout=timeout

cylc/flow/scripts/clean.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,11 @@ def get_option_parser():
120120

121121
parser.add_option(
122122
'--timeout',
123-
help=("The number of seconds to wait for cleaning to take place on "
124-
r"remote hosts before cancelling. Default: %default."),
125-
action='store', default='120', dest='remote_timeout'
123+
help=(
124+
"The length of time to wait for cleaning to take place on "
125+
r"remote hosts before cancelling. Default: %default."
126+
),
127+
action='store', default='PT5M', dest='remote_timeout'
126128
)
127129

128130
parser.add_option(

tests/unit/test_clean.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import shutil
2020
from glob import iglob
2121
from pathlib import Path
22+
from subprocess import Popen
2223
from typing import (
2324
Any,
2425
Callable,
@@ -274,7 +275,8 @@ def test_init_clean__rm_dirs(
274275
init_clean(id_, opts=opts)
275276
mock_clean.assert_called_with(id_, run_dir, expected_clean)
276277
mock_remote_clean.assert_called_with(
277-
id_, platforms, expected_remote_clean, opts.remote_timeout)
278+
id_, platforms, opts.remote_timeout, expected_remote_clean
279+
)
278280

279281

280282
@pytest.mark.parametrize(
@@ -920,7 +922,7 @@ def test_remote_clean(
920922
# Remove randomness:
921923
monkeymock('cylc.flow.clean.shuffle')
922924

923-
def mocked_remote_clean_cmd_side_effect(id_, platform, rm_dirs, timeout):
925+
def mocked_remote_clean_cmd_side_effect(id_, platform, timeout, rm_dirs):
924926
proc_ret_code = 0
925927
if failed_platforms and platform['name'] in failed_platforms:
926928
proc_ret_code = failed_platforms[platform['name']]
@@ -942,11 +944,13 @@ def mocked_remote_clean_cmd_side_effect(id_, platform, rm_dirs, timeout):
942944
if exc_expected:
943945
with pytest.raises(CylcError) as exc:
944946
cylc_clean.remote_clean(
945-
id_, platform_names, rm_dirs, timeout='irrelevant')
947+
id_, platform_names, timeout='irrelevant', rm_dirs=rm_dirs
948+
)
946949
assert "Remote clean failed" in str(exc.value)
947950
else:
948951
cylc_clean.remote_clean(
949-
id_, platform_names, rm_dirs, timeout='irrelevant')
952+
id_, platform_names, timeout='irrelevant', rm_dirs=rm_dirs
953+
)
950954
for msg in expected_err_msgs:
951955
assert log_filter(caplog, level=logging.ERROR, contains=msg)
952956
if expected_platforms:
@@ -960,6 +964,33 @@ def mocked_remote_clean_cmd_side_effect(id_, platform, rm_dirs, timeout):
960964
assert f"{p_name} - {PlatformError.MSG_TIDY}" in caplog.text
961965

962966

967+
@pytest.mark.parametrize(
968+
'timeout, expected',
969+
[('100', '100'),
970+
('PT1M2S', '62.0')]
971+
)
972+
def test_remote_clean__timeout(
973+
monkeymock: MonkeyMock, monkeypatch: pytest.MonkeyPatch,
974+
timeout: str, expected: str,
975+
):
976+
"""Test that remote_clean() accepts a timeout in ISO 8601 format or
977+
number of seconds."""
978+
mock_remote_clean_cmd = monkeymock(
979+
'cylc.flow.clean._remote_clean_cmd',
980+
spec=_remote_clean_cmd,
981+
return_value=mock.Mock(
982+
spec=Popen, poll=lambda: 0, communicate=lambda: ('', '')
983+
)
984+
)
985+
monkeypatch.setattr(
986+
'cylc.flow.clean.get_install_target_to_platforms_map',
987+
lambda *a, **k: {'picard': [PLATFORMS['stargazer']]}
988+
)
989+
990+
cylc_clean.remote_clean('blah', 'blah', timeout)
991+
assert mock_remote_clean_cmd.call_args.kwargs['timeout'] == expected
992+
993+
963994
@pytest.mark.parametrize(
964995
'rm_dirs, expected_args',
965996
[

0 commit comments

Comments
 (0)