# Robust coding of expired tasks

**URL:** <https://cylc.discourse.group/t/robust-coding-of-expired-tasks/230>\
**Category:** Cylc Support\
**Created:** [April 15, 2020, 4:27am UTC](https://cylc.discourse.group/t/robust-coding-of-expired-tasks/230 "2020-04-15T04:27:42Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![fredw](https://yyz2.discourse-cdn.com/free1/user_avatar/cylc.discourse.group/fredw/32/112_2.png) [@fredw](https://cylc.discourse.group/u/fredw)\
**Post date:** [April 15, 2020, 4:27am UTC](https://cylc.discourse.group/t/robust-coding-of-expired-tasks/230/1 "2020-04-15T04:27:42Z")

</div>

I use cylc 7.8.1. Per cycle point all my tasks lead to a housekeep task, which uses rose\_prune to tidy up logs/work/share etc. So without the housekeep task being triggered the suite will eventually fail to advance.

In this example I have tasks that copy data which doesn’t exist when the suite gets too far behind wall-clock time. I think I got this right by writing:

```
[[[T12]]]
    graph = """
        copy | copy:expired => housekeep
    """

```

This is the simplest case. Could I write this in a shorter way as copy:finish =\> housekeep ? Does :finish include :succeeded and :expired?

In a more complex case I create a plot from this copied data and other local model output which is polled for by a polling task (succeeds if local file exists, typically fails a couple of times before eventually succeeding, but may expire). The plotting shouldn’t happen if the polled data has expired, neither should it plot when the copied data has expired. But if poll and copy expire (and plot never happened), the housekeeping should still run. The thing with the polling task is that I can reasonably trust for this local data to eventually turn up (but I still want to handle expiry as there is no use in plotting data from weeks ago). The copy task on the other hand is less robust and data may never turn up. So the copy task should be allowed to fail without holding up the rest of the suite.

This is what I came up with to achieve this behaviour, and I am wondering whether it is complete:

```
[[[T12]]]
    graph = """
        poll & copy => plot
        poll:expired => !plot
        copy:expired => !plot
        copy:fail => !plot
        poll:expired | copy:expired | copy:fail | plot => housekeep
"""

```

Thanks for any comments and hints!  
Fred

---

<div class="post-metadata">

**Author:** ![hilary.j.oliver](https://yyz2.discourse-cdn.com/free1/user_avatar/cylc.discourse.group/hilary.j.oliver/32/4_2.png) [@hilary.j.oliver](https://cylc.discourse.group/u/hilary.j.oliver)\
**Post date:** [April 15, 2020, 10:15pm UTC](https://cylc.discourse.group/t/robust-coding-of-expired-tasks/230/2 "2020-04-15T22:15:26Z")

</div>

Hi Fred,

> [@fredw](#):
>
> Could I write this in a shorter way as copy:finish =\> housekeep ? Does :finish include :succeeded and :expired?

No, `copy:finish` is short for `copy:succeed | copy:fail`, i.e. “finished executing”. Whereas `copy:expired` means don’t bother executing task `copy` because it is too far behind the clock.

If I understand the description of your workflow properly, your graph should look something like this:

```auto
[[[T12]]]
    graph = """
        poll & copy => plot
        poll:expired | copy:expired | copy:fail => !plot & no_plot
        plot | no_plot => housekeep
            """

```

To explain:

Separate triggers for the same task are equivalent to AND. So this:

```auto
a => plot
b => plot

```

is equivalent to this:

```auto
a & b => plot

```

And the same goes for suicide triggers:

```auto
poll:expire => !plot
copy:expire => !plot
copy:fail => !plot

```

is equivalent to:

```auto
poll:expire & copy:expire & copy:fail => !plot

```

i.e. BOTH poll AND copy have to expire, AND copy has to fail, for plot to be removed from the workflow - which ain’t gonna happen. From your description, you really want this:

```auto
poll:expired | copy:expired | copy:fail => !plot

```

The other change is optional: I’ve used a dummy task `no_plot` to signify that `plot` was removed and no plotting was done. Then you can explicitly trigger housekeeping off of plot or no\_plot:

```auto
        poll:expired | copy:expired | copy:fail => !plot & no_plot
        plot | no_plot => housekeep

```

I happen to think that’s easier to understand, but you could stick to your original housekeep trigger line:

```auto
        poll:expired | copy:expired | copy:fail => !plot
        poll:expired | copy:expired | copy:fail | plot => housekeep

```

Note (just in case I’ve got it wrong!) you should be able to test this with a dummy suite (i.e. just your graph with `sleep 10` tasks or whatever) with initial cycle point and clock and expire triggers contrived so that you don’t have to wait long to see what happens.

Hope that helps.

Hilary

---

<div class="post-metadata">

**Author:** ![fredw](https://yyz2.discourse-cdn.com/free1/user_avatar/cylc.discourse.group/fredw/32/112_2.png) [@fredw](https://cylc.discourse.group/u/fredw)\
**Post date:** [April 16, 2020, 5:16am UTC](https://cylc.discourse.group/t/robust-coding-of-expired-tasks/230/3 "2020-04-16T05:16:20Z")

</div>

Thank you so much! Your explanations are very clear.

I programmed the suite according to your last suggestion:

> poll:expired | copy:expired | copy:fail =\> !plot  
> poll:expired | copy:expired | copy:fail | plot =\> housekeep

I find it easier to get my head round it, as I was a bit scared of introducing a dummy task.

Again, thanks very much. Your help is a life-line!

---

<div class="post-metadata">

**Author:** ![fredw](https://yyz2.discourse-cdn.com/free1/user_avatar/cylc.discourse.group/fredw/32/112_2.png) [@fredw](https://cylc.discourse.group/u/fredw)\
**Post date:** [October 4, 2023, 5:15pm UTC](https://cylc.discourse.group/t/robust-coding-of-expired-tasks/230/4 "2023-10-04T17:15:13Z")

</div>

Hello @hilary.j.oliver

I have come back to look at suicide triggers in my workflow as I am porting them to cylc8.  
How should this be done in cylc8?

My suites have tons of these constructs in them (inspired by the original replies above):

```auto
            graph = """
                download => run_processing => merge_files
                download:expired => !run_processing
                download:expired | run_processing:expired => !merge_files
                download:expired | run_processing:expired | merge_files => housekeep
...

```

---

<div class="post-metadata">

**Author:** ![hilary.j.oliver](https://yyz2.discourse-cdn.com/free1/user_avatar/cylc.discourse.group/hilary.j.oliver/32/4_2.png) [@hilary.j.oliver](https://cylc.discourse.group/u/hilary.j.oliver)\
**Post date:** [October 4, 2023, 8:27pm UTC](https://cylc.discourse.group/t/robust-coding-of-expired-tasks/230/5 "2023-10-04T20:27:44Z")

</div>

> I have come back to look at suicide triggers in my workflow

Good news, you can remove them all.

In Cylc 7-, suicide triggers had to be used to clean up graph branches not taken at run time, because the scheduler would pre-spawn upcoming instances of all tasks to be available _if needed_. The Cylc 8 scheduling algorithm is event-driven - tasks spawn on-demand as upstream outputs are generated. So suicide triggers are no longer needed, in general.

[https://cylc.github.io/cylc-doc/stable/html/user-guide/writing-workflows/suicide-triggers.html#suicide-triggers](https://cylc.github.io/cylc-doc/stable/html/user-guide/writing-workflows/suicide-triggers.html#suicide-triggers)

---

<div class="post-metadata">

**Author:** ![fredw](https://yyz2.discourse-cdn.com/free1/user_avatar/cylc.discourse.group/fredw/32/112_2.png) [@fredw](https://cylc.discourse.group/u/fredw)\
**Post date:** [October 5, 2023, 10:39am UTC](https://cylc.discourse.group/t/robust-coding-of-expired-tasks/230/6 "2023-10-05T10:39:17Z")

</div>

Thanks, that is good news indeed, because long chains of branching tasks coded with suicide triggers were becoming unmaintanable after a certain chain length.

But my question remains - what do I do with this construct I mentioned above.

I want the post-processing of the downloaded file and the merging of that processed file into the downloaded file to be omitted only if the download expired (the server only keeps files online for 7 days , so it’s pointless attempting the download after that, hence the expiration)

In this discussion [Workflow with suicide triggers](https://cylc.discourse.group/t/workflow-with-suicide-triggers/499) I saw the construct

```auto
@clock => a? => b? => c?
a:finish => housekeeping

```

So can I translate my above construct into cylc8 like this?

```auto
    download => run_processing? => merge_files? => housekeep?

```

or like this?

```auto
    download? => run_processing? => merge_files? => housekeep

```

where do the question marks go?

Thanks!

---

<div class="post-metadata">

**Author:** ![MetRonnie](https://yyz2.discourse-cdn.com/free1/user_avatar/cylc.discourse.group/metronnie/32/125_2.png) [@MetRonnie](https://cylc.discourse.group/u/MetRonnie)\
**Post date:** [October 5, 2023, 11:36am UTC](https://cylc.discourse.group/t/robust-coding-of-expired-tasks/230/7 "2023-10-05T11:36:31Z")

</div>

The question marks go where you do not want the scheduler to stall if that task did not succeed. So if it’s the `download` task that you are handling not succeeding, you would just do:

```auto
download? => run_processing => merge_files => housekeep

```

But if you want `housekeep` to run if `download` expired too then I think you would need to do something like

```auto
download? => run_processing => merge_files
(download:expired | merge_files ) => housekeep

```

---

<div class="post-metadata">

**Author:** ![fredw](https://yyz2.discourse-cdn.com/free1/user_avatar/cylc.discourse.group/fredw/32/112_2.png) [@fredw](https://cylc.discourse.group/u/fredw)\
**Post date:** [October 5, 2023, 12:06pm UTC](https://cylc.discourse.group/t/robust-coding-of-expired-tasks/230/8 "2023-10-05T12:06:31Z")

</div>

Oh wonderful. Thank you so much. That makes this type of chain a bit simpler.

I have several versions of a more complicated version of this scheme:

```auto
            graph = """
                get_gfs & (get_sst[+PT18H] | get_sst[+PT18H]:expired) => convert_gfs => housekeep
                get_gfs:succeed => ! expire_convert_gfs
                get_gfs:expired => expire_convert_gfs
                get_gfs:expired | convert_gfs | convert_gfs:expired => housekeep
            """

```

It’s supposed to download the GFS data and the SST data (for +PT18H), then convert the GFS+SST data. But the SST data is optional for th `convert_gfs` task, if the SST files have already expired the `convert_gfs` task can run without SST (the GFS data is online for longer than the SST data, so `get_sst` might expire first)

But `get_gfs` might also expire, and in that case we don’t need to run `convert_gfs` at all. In cylc7 I had a task called `expire_convert_gfs` that uses `cylc set-outputs ... --output=expired` to expire the conversion task. It sounds like this is no longer needed.

So I re-wrote the whole thing like this:

```auto
            graph = """
                (get_gfs & (get_sst[+PT18H] | get_sst[+PT18H]:expired))? => convert_gfs
                (get_gfs:expired | convert_gfs) => housekeep
            """

```

Does that look correct?

Thanks!

---

<div class="post-metadata">

**Author:** ![MetRonnie](https://yyz2.discourse-cdn.com/free1/user_avatar/cylc.discourse.group/metronnie/32/125_2.png) [@MetRonnie](https://cylc.discourse.group/u/MetRonnie)\
**Post date:** [October 5, 2023, 3:11pm UTC](https://cylc.discourse.group/t/robust-coding-of-expired-tasks/230/9 "2023-10-05T15:11:39Z")

</div>

Ah unfortunately I had forgotten that the `:expired` trigger is currently broken, pending a fix targeted for Cylc 8.3.0 - [:expire trigger broken · Issue #5364 · cylc/cylc-flow · GitHub](https://github.com/cylc/cylc-flow/issues/5364).

Additionally the `:expired` trigger is going to be incorporated in the optional outputs scheme so will need a question mark. So ultimately I think what you’ll be after is this:

```txt
get_gfs? => convert_gfs
(get_sst[+PT18H]? | get_sst[+PT18H]:expired?) => convert_gfs
(get_gfs:expired? | convert_gfs) => housekeep

```

but I’m afraid it won’t work until 8.3.0 is released.

- Note it isn’t valid to put a question mark after parentheses the way you did
- Instead of using an AND operator I’ve split your first line into two for readability, but both do the same thing

---

<div class="post-metadata">

**Author:** ![fredw](https://yyz2.discourse-cdn.com/free1/user_avatar/cylc.discourse.group/fredw/32/112_2.png) [@fredw](https://cylc.discourse.group/u/fredw)\
**Post date:** [October 5, 2023, 3:43pm UTC](https://cylc.discourse.group/t/robust-coding-of-expired-tasks/230/10 "2023-10-05T15:43:30Z")

</div>

> [@MetRonnie](#):
>
> ```auto
> get_gfs? => convert_gfs
> (get_sst[+PT18H]? | get_sst[+PT18H]:expired?) => convert_gfs
> (get_gfs:expired? | convert_gfs) => housekeep
> 
> ```

That notation makes a lot of sense. Making suites deal with expiring tasks is not the most important thing as it only serves to recover from rare errors. It makes the suites more resilient, but it can wait for the next version. So I changed my graphs according to your suggestions, and the validation is OK.

Thanks for taking the time to reply 🙂  
Fred
