Workflows
A PERSEUS workflow automates an operation on a project: when something happens (a trigger), if the project is in a certain shape (conditions), do this (actions).
Workflows are created and managed centrally in the workflow registry. A project only reacts to a workflow once it is subscribed to it, which is managed from the project details view. The same workflow can be subscribed to by many projects at once.
Triggers
Section titled “Triggers”A trigger decides when a workflow should be checked. A workflow can have several triggers, and they are combined with OR — the workflow is checked whenever any one of them fires.
- Time trigger: a cron schedule expression with five fields (minute,
hour, day of month, month, day of week, where
0is Sunday), for example0 3 * * *for daily at 3 AM UTC.*,*/n(every n units) and comma-separated lists are supported. Ranges (e.g.1-5), named months or weekdays, six-field schedules, and shorthand macros such as@dailyare not supported — use the equivalent five-field expression instead. - Event trigger: fires when a named event occurs elsewhere in PERSEUS, for example when a project changes state. If the event is tied to a specific project, only that project’s subscription reacts; otherwise every subscribed project does.
Conditions
Section titled “Conditions”A condition is a short, python-like expression that must evaluate to True for the workflow’s actions to run, for
example:
end - now < timedelta(days=30)It is never executed with Python’s eval(). Instead it is parsed once when you save it and evaluated in a restricted
sandbox that only ever sees the names and functions listed below — there are no imports, no builtins and no way to
reach outside of it.
A workflow with no conditions always runs once triggered.
Available names
Section titled “Available names”| Name | Type | Meaning |
|---|---|---|
any Project attribute | — | e.g. title, abbreviation, start, end, member_ids, granted_resources |
project | Project | the project itself, if you prefer project.title over title |
current_states | list[str] | the currently active states of the project |
now | datetime | the moment the workflow is being checked |
JobState | enum | so you can write JobState.RUNNING |
Available functions
Section titled “Available functions”Besides abs, all, any, datetime, float, int, len, max, min, round, sorted, str, sum and
timedelta, the following are available:
| Function | Returns |
|---|---|
matches(value, pattern) | True if the regular expression pattern is found in str(value) |
get_item(array, criteria) | the first item in array matching every key in criteria, or None |
get_jobs(...) | the project’s jobs, optionally filtered by cluster, partition, state, priority, or submitted/started/ended time ranges |
get_usage_total(resource_id, ...) | total usage of a resource across all phases |
get_usage_current_phase(resource_id, ...) | usage of a resource within the current phase only |
get_used_contingent_total(resource_id, ...) | same as get_usage_total, but as a share of the granted contingent |
get_used_contingent_current_phase(resource_id, ...) | same as get_used_contingent_total, restricted to the current phase |
Examples
Section titled “Examples”"'ComputeProjectRunning' in current_states""end is not None and end - now < timedelta(days=30)""matches(abbreviation, '^HPC-')""len(get_jobs(state=JobState.RUNNING)) > 100""get_usage_current_phase('core-h') > 0.9 * 1_000_000"Combining multiple conditions
Section titled “Combining multiple conditions”Each condition (except the last) has an and/or operator that connects it to the next condition. The list is
combined strictly from left to right, without normal operator precedence:
[a (or), b (and), c] → (a or b) and cPut cheap checks first and expensive ones (such as get_jobs or the usage functions) last — evaluation short-circuits,
so a condition that can no longer change the result is never evaluated.
Actions
Section titled “Actions”Actions run in the order they are configured. If one fails, the remaining actions for that run are skipped. Currently available actions:
- Send email: sends a formatted email to the project’s principal
investigator (
PI), person of contact (PC), a specific person, or a literal email address. The subject, content, and optional call-to-action button text/URL may contain placeholders that are filled in for the project at the moment the email is sent. - Trigger event: emits a named event, optionally with a fixed payload, which other workflows can react to via an event trigger. The current project and workflow are always added to the payload automatically.
How workflows are executed
Section titled “How workflows are executed”PERSEUS checks all workflows once every minute rather than reacting instantly. For each project subscribed to a workflow whose trigger fired, the following is checked, from cheapest to most expensive, before any conditions are evaluated:
- Is the subscription enabled?
- Are we within the subscription’s (or, if unset, the project’s) start/end window?
- Does the trigger that fired apply to this project?
- Has the workflow’s maximum number of repetitions already been reached for this project? This counter is cumulative for the project and is not reset by disabling and re-enabling the subscription.
- Has the configured cooldown since the last execution already elapsed? The cooldown always takes precedence over the trigger — even if the trigger fires again, the workflow will not run again until the cooldown has passed.
Only once every one of these passes are the workflow’s conditions evaluated. If they hold, the actions run in order and the outcome is recorded, which is what drives the execution history shown in the project details view.