Hera Core Concepts
This page discusses the core concepts of Argo Workflows in the context of Hera.
The Workflow class
The Workflow holds a collection of templates, and runs the
entrypoint template, usually a DAG or Steps template. In Hera, the Workflow is a context manager, so it loosely
mirrors the YAML dictionary structure, and adds any templates created or referenced under it.
Here is a simple “Hello World” example:
from hera.workflows import Steps, Workflow, WorkflowsService, script
@script()
def echo(message: str):
print(message)
with Workflow(
generate_name="hello-world-",
entrypoint="steps",
namespace="argo",
workflows_service=WorkflowsService(host="https://localhost:2746")
) as w:
with Steps(name="steps"):
echo(arguments={"message": "Hello world!"})
w.create()
Learn more about basics of Hera Workflows in the walk-through!
The WorkflowTemplate
A WorkflowTemplate is a library of templates that live on your cluster and can be referenced by other Workflows and WorkflowTemplates.
When creating a WorkflowTemplate in YAML, a developer would usually iterate on a Workflow and convert it later. Hera
allows you to start with a WorkflowTemplate, and create instances from it as you develop and test it.
from hera.workflows import Steps, WorkflowTemplate, WorkflowsService, script
@script()
def echo(message: str):
print(message)
with WorkflowTemplate(
name="my-hello-world-template",
entrypoint="steps",
namespace="argo",
workflows_service=WorkflowsService(host="https://localhost:2746")
) as w:
with Steps(name="steps"):
echo(arguments={"message": "Hello world!"})
w.create_as_workflow() # This will create a Workflow with a name like "my-hello-world-templateaxyqb" on your cluster!
If you’d like to create a Workflow with a different name to find these iterative Workflows more easily, you can simply
pass the generate_name argument:
This will create a Workflow with a name like test-hello-world-template-lqoix on your cluster.
Template Classes
Container
A container requires a name, image and command (with args if required):
from hera.workflows import Container
Container(
name="whalesay",
image="docker/whalesay",
command=["cowsay"],
args=["hello world"],
)
Script
Script templates are a convenience wrapper for Containers. Hera lets you write Python functions directly as Script
templates, using the @script decorator:
Read more in the Script decorator section.
Resource
Resource templates perform operations on cluster resources directly. You can get, create, apply, delete, replace, or patch resources.
This is the k8s_set_owner_reference example:
from hera.workflows import Resource, Workflow
manifest = """apiVersion: v1
kind: ConfigMap
metadata:
generateName: owned-eg-
data:
some: value\n"""
with Workflow(
generate_name="k8s-set-owner-reference-",
entrypoint="k8s-set-owner-reference",
) as w:
create_route = Resource(
name="k8s-set-owner-reference",
action="create",
manifest=manifest,
set_owner_reference=True,
)
The manifest of a Resource supports passing Workflow objects for the
workflow-of-workflows pattern. This is the
workflow_of_workflows example:
from hera.workflows import Container, Resource, Step, Steps, Workflow
with Workflow(
generate_name="sub-workflow-,
entrypoint="echo",
) as sub_workflow:
Container(
name="echo",
image="docker/whalesay:latest",
command=["whalesay"],
args=["I'm in another workflow!"],
)
with Workflow(generate_name="workflow-of-workflows-", entrypoint="main") as w:
workflow_resource = Resource(
name="workflow-resource",
action="create",
manifest=sub_workflow,
success_condition="status.phase == Succeeded",
failure_condition="status.phase in (Failed, Error)",
)
with Steps(name="main"):
Step(name="sub-workflow", template=workflow_resource)
Suspend
Suspend is a simple template that halts execution of the Workflow for a specified duration, or a manual resume.
Suspend templates are used for
intermediate parameters, which in Hera are simplified
and easier to use. Read more in the suspending guide!
Template invocators
Template invocators are used to arrange template execution order, and are templates themselves, so can in fact recursively call themselves (ensure you have a stopping condition!).
Steps
Steps are created by first creating a Steps context, and then creating Step objects within it, each specifying a
template to run. By default, they run in sequence, but can run in parallel by creating a sub-context with parallel().
The following is the steps example from the upstream examples collection:
from hera.workflows import Container, Parameter, Step, Steps, Workflow
with Workflow(
generate_name="steps-",
entrypoint="hello-hello-hello",
) as w:
whalesay = Container(
name="whalesay",
inputs=[Parameter(name="message")],
image="docker/whalesay",
command=["cowsay"],
args=["{{inputs.parameters.message}}"],
)
with Steps(name="hello-hello-hello") as s:
Step(
name="hello1",
template="whalesay",
arguments={"message": "hello1"},
)
with s.parallel():
Step(
name="hello2a",
template="whalesay",
arguments={"message": "hello2a"},
)
Step(
name="hello2b",
template="whalesay",
arguments={"message": "hello2b"},
)
Functions decorated with @script also work in the same way under Steps:
from hera.workflows import Steps, WorkflowTemplate, script
@script()
def echo(message: str):
print(message)
with Workflow(
name="hello-world-steps",
entrypoint="steps",
) as w:
with Steps(name="steps"):
echo(name="echo1", arguments={"message": "Hello 1"})
echo(name="echo2", arguments={"message": "Hello 2"})
Read more about Steps in the walk-through!
DAG
A DAG is composed of Tasks with dependencies to form an acyclic graph. The syntax in Hera is similar to Steps, but with the rshift syntax for specifying simple Task dependencies.
from hera.workflows import DAG, Workflow, script
@script()
def echo(message):
print(message)
with Workflow(generate_name="dag-diamond-", entrypoint="diamond") as w:
with DAG(name="diamond"):
A = echo(name="A", arguments={"message": "A"})
B = echo(name="B", arguments={"message": "B"})
C = echo(name="C", arguments={"message": "C"})
D = echo(name="D", arguments={"message": "D"})
A >> [B, C] >> D
Read more about DAGs in the walk-through!