Skip to content

Commit ae6a70d

Browse files
sequential clock spawning fix (#6206)
sequential clock spawning fix --------- Co-authored-by: Ronnie Dutta <[email protected]>
1 parent bb64e9f commit ae6a70d

File tree

3 files changed

+47
-26
lines changed

3 files changed

+47
-26
lines changed

changes.d/6206.fix.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixes the spawning of multiple parentless tasks off the same sequential wall-clock xtrigger.

cylc/flow/xtrigger_mgr.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,8 @@ def call_xtriggers_async(self, itask: 'TaskProxy'):
644644
if sig in self.sat_xtrig:
645645
# Already satisfied, just update the task
646646
itask.state.xtriggers[label] = True
647+
if self.all_task_seq_xtriggers_satisfied(itask):
648+
self.sequential_spawn_next.add(itask.identity)
647649
elif _wall_clock(*ctx.func_args, **ctx.func_kwargs):
648650
# Newly satisfied
649651
itask.state.xtriggers[label] = True

tests/integration/test_xtrigger_mgr.py

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,14 @@
1818
import asyncio
1919
from pathlib import Path
2020
from textwrap import dedent
21+
from typing import Set
2122

2223
from cylc.flow.pathutil import get_workflow_run_dir
24+
from cylc.flow.scheduler import Scheduler
25+
26+
27+
def get_task_ids(schd: Scheduler) -> Set[str]:
28+
return {task.identity for task in schd.pool.get_tasks()}
2329

2430

2531
async def test_2_xtriggers(flow, start, scheduler, monkeypatch):
@@ -38,9 +44,6 @@ async def test_2_xtriggers(flow, start, scheduler, monkeypatch):
3844
lambda: ten_years_ahead - 1
3945
)
4046
id_ = flow({
41-
'scheduler': {
42-
'allow implicit tasks': True
43-
},
4447
'scheduling': {
4548
'initial cycle point': '2020-05-05',
4649
'xtriggers': {
@@ -72,31 +75,19 @@ async def test_2_xtriggers(flow, start, scheduler, monkeypatch):
7275
}
7376

7477

75-
async def test_1_xtrigger_2_tasks(flow, start, scheduler, monkeypatch, mocker):
78+
async def test_1_xtrigger_2_tasks(flow, start, scheduler, mocker):
7679
"""
7780
If multiple tasks depend on the same satisfied xtrigger, the DB mgr method
78-
put_xtriggers should only be called once - when the xtrigger gets satisfied.
81+
put_xtriggers should only be called once - when the xtrigger gets satisfied
7982
8083
See [GitHub #5908](https://github.com/cylc/cylc-flow/pull/5908)
8184
8285
"""
83-
task_point = 1588636800 # 2020-05-05
84-
ten_years_ahead = 1904169600 # 2030-05-05
85-
monkeypatch.setattr(
86-
'cylc.flow.xtriggers.wall_clock.time',
87-
lambda: ten_years_ahead - 1
88-
)
8986
id_ = flow({
90-
'scheduler': {
91-
'allow implicit tasks': True
92-
},
9387
'scheduling': {
94-
'initial cycle point': '2020-05-05',
95-
'xtriggers': {
96-
'clock_1': 'wall_clock()',
97-
},
88+
'initial cycle point': '2020',
9889
'graph': {
99-
'R1': '@clock_1 => foo & bar'
90+
'R1': '@wall_clock => foo & bar'
10091
}
10192
}
10293
})
@@ -112,7 +103,7 @@ async def test_1_xtrigger_2_tasks(flow, start, scheduler, monkeypatch, mocker):
112103
schd.xtrigger_mgr.call_xtriggers_async(task)
113104

114105
# It should now be satisfied.
115-
assert task.state.xtriggers == {'clock_1': True}
106+
assert task.state.xtriggers == {'wall_clock': True}
116107

117108
# Check one put_xtriggers call only, not two.
118109
assert spy.call_count == 1
@@ -128,9 +119,6 @@ async def test_xtriggers_restart(flow, start, scheduler, db_select):
128119
"""It should write xtrigger results to the DB and load them on restart."""
129120
# define a workflow which uses a custom xtrigger
130121
id_ = flow({
131-
'scheduler': {
132-
'allow implicit tasks': 'True'
133-
},
134122
'scheduling': {
135123
'xtriggers': {
136124
'mytrig': 'mytrig()'
@@ -194,9 +182,6 @@ async def test_error_in_xtrigger(flow, start, scheduler):
194182
"""Failure in an xtrigger is handled nicely.
195183
"""
196184
id_ = flow({
197-
'scheduler': {
198-
'allow implicit tasks': 'True'
199-
},
200185
'scheduling': {
201186
'xtriggers': {
202187
'mytrig': 'mytrig()'
@@ -231,3 +216,36 @@ def mytrig(*args, **kwargs):
231216
error = log.messages[-1].split('\n')
232217
assert error[-2] == 'Exception: This Xtrigger is broken'
233218
assert error[0] == 'ERROR in xtrigger mytrig()'
219+
220+
221+
async def test_1_seq_clock_trigger_2_tasks(flow, start, scheduler):
222+
"""Test that all tasks dependent on a sequential clock trigger continue to
223+
spawn after the first cycle.
224+
225+
See https://github.com/cylc/cylc-flow/issues/6204
226+
"""
227+
id_ = flow({
228+
'scheduler': {
229+
'cycle point format': 'CCYY',
230+
},
231+
'scheduling': {
232+
'initial cycle point': '1990',
233+
'graph': {
234+
'P1Y': '@wall_clock => foo & bar',
235+
},
236+
},
237+
})
238+
schd: Scheduler = scheduler(id_)
239+
240+
async with start(schd):
241+
start_task_pool = get_task_ids(schd)
242+
assert start_task_pool == {'1990/foo', '1990/bar'}
243+
244+
for _ in range(3):
245+
await schd._main_loop()
246+
247+
assert get_task_ids(schd) == start_task_pool.union(
248+
f'{year}/{name}'
249+
for year in range(1991, 1994)
250+
for name in ('foo', 'bar')
251+
)

0 commit comments

Comments
 (0)