Skip to content

Suspending Workflows

A user can pause execution of a Workflow at any time through the Argo UI, or the Argo CLI using argo suspend, and resume the Workflow in the UI or with argo resume.

In Hera, you can suspend a Workflow at specific points using Suspend templates, making it easy to set up human-in-the-loop workflows.

Basic Suspend Usage

Use a Suspend template to pause the Workflow at any point in a Steps or DAG context. This Workflow will wait until a user manually resumes the Workflow (in the UI or CLI):

@script()
def echo(message: str):
    print(message)


with Workflow(
    generate_name="suspending-workflow-",
    entrypoint="steps",
) as w:

    suspend_template = Suspend(name="wait-for-resume")

    with Steps(name="steps"):
        echo(name="s1", arguments={"message": "The next node waits until you resume the workflow"})
        suspend_template(name="suspend")
        echo(name="s2", arguments={"message": "Finished waiting!"})
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: suspending-workflow-
spec:
  entrypoint: steps
  templates:
  - name: wait-for-resume
    suspend: {}
  - name: steps
    steps:
    - - name: s1
        template: echo
        arguments:
          parameters:
          - name: message
            value: The next node waits until you resume the workflow
    - - name: suspend
        template: wait-for-resume
    - - name: s2
        template: echo
        arguments:
          parameters:
          - name: message
            value: Finished waiting!
  - name: echo
    inputs:
      parameters:
      - name: message
    script:
      image: python:3.10
      source: |-
        import os
        import sys
        sys.path.append(os.getcwd())
        import json
        try: message = json.loads(r'''{{inputs.parameters.message}}''')
        except: message = r'''{{inputs.parameters.message}}'''

        print(message)
      command:
      - python

Timed Suspend Usage

To pause the Workflow for a specific length of time, pass a value to the Suspend template’s duration variable. A user can still manually resume the Workflow before the time is up:

@script()
def echo(message: str):
    print(message)


with Workflow(
    generate_name="suspending-workflow-",
    entrypoint="steps",
) as w:

    suspend_template = Suspend(name="wait-10-seconds", duration=10)

    with Steps(name="steps"):
        echo(name="s1", arguments={"message": "The next node will wait for 10 seconds"})
        suspend_template(name="suspend")
        echo(name="s2", arguments={"message": "Finished waiting!"})
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: suspending-workflow-
spec:
  entrypoint: steps
  templates:
  - name: wait-10-seconds
    suspend:
      duration: '10'
  - name: steps
    steps:
    - - name: s1
        template: echo
        arguments:
          parameters:
          - name: message
            value: The next node will wait for 10 seconds
    - - name: suspend
        template: wait-10-seconds
    - - name: s2
        template: echo
        arguments:
          parameters:
          - name: message
            value: Finished waiting!
  - name: echo
    inputs:
      parameters:
      - name: message
    script:
      image: python:3.10
      source: |-
        import os
        import sys
        sys.path.append(os.getcwd())
        import json
        try: message = json.loads(r'''{{inputs.parameters.message}}''')
        except: message = r'''{{inputs.parameters.message}}'''

        print(message)
      command:
      - python

Intermediate Parameters

Intermediate Parameters are an Argo UI feature that pause a Workflow to wait for user input values.

This Workflow suspends indefinitely, waiting for user input, and echoes the user’s input in the next Step:

@script()
def echo(message: str):
    print(message)


with Workflow(
    generate_name="intermediate-parameter-workflow-",
    entrypoint="steps",
) as w:

    suspend_template = Suspend(
        name="suspend-with-intermediate-param",
        intermediate_parameters=[Parameter(name="my-message", default="")],
    )

    with Steps(name="steps"):
        suspend_step = suspend_template(name="suspend")
        echo(arguments={"message": suspend_step.get_parameter("my-message")})
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: intermediate-parameter-workflow-
spec:
  entrypoint: steps
  templates:
  - name: suspend-with-intermediate-param
    inputs:
      parameters:
      - name: my-message
        default: ''
    outputs:
      parameters:
      - name: my-message
        valueFrom:
          supplied: {}
    suspend: {}
  - name: steps
    steps:
    - - name: suspend
        template: suspend-with-intermediate-param
    - - name: echo
        template: echo
        arguments:
          parameters:
          - name: message
            value: '{{steps.suspend.outputs.parameters.my-message}}'
  - name: echo
    inputs:
      parameters:
      - name: message
    script:
      image: python:3.10
      source: |-
        import os
        import sys
        sys.path.append(os.getcwd())
        import json
        try: message = json.loads(r'''{{inputs.parameters.message}}''')
        except: message = r'''{{inputs.parameters.message}}'''

        print(message)
      command:
      - python

We can also * restrict input options using a list of values passed to enum * set a pre-selected default * and set a duration to effectively time-out on the user input (using a suitable when expression):

@script()
def deploy():
    print("Deploying!")


with Workflow(
    generate_name="approval-workflow-",
    entrypoint="steps",
) as w:

    approval_template = Suspend(
        name="approval",
        intermediate_parameters=[Parameter(name="approve", default="NO", enum=["YES", "NO"])],
        duration="4h",
    )

    with Steps(name="steps"):
        approval = approval_template(name="suspend")
        deploy(when=f'{approval.get_parameter("approve")} == "YES"')
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: approval-workflow-
spec:
  entrypoint: steps
  templates:
  - name: approval
    inputs:
      parameters:
      - name: approve
        default: 'NO'
        enum:
        - 'YES'
        - 'NO'
    outputs:
      parameters:
      - name: approve
        valueFrom:
          supplied: {}
    suspend:
      duration: 4h
  - name: steps
    steps:
    - - name: suspend
        template: approval
    - - name: deploy
        template: deploy
        when: '{{steps.suspend.outputs.parameters.approve}} == "YES"'
  - name: deploy
    script:
      image: python:3.10
      source: |-
        import os
        import sys
        sys.path.append(os.getcwd())
        print('Deploying!')
      command:
      - python

Comments