---
title: "Concepts"
description: "Apps, workflows, runs, steps, invocations and replay."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.ezghcloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Concepts

## Terms

| Term | Meaning |
| --- | --- |
| App | One deployment of your code that hosts workflows, in a project. A **push** app has an HTTPS endpoint that EZGH calls. A **pull** app has a task queue that your workers poll. Its ID is a UUID, and its slug starts with `wfa_`. See [Push and pull apps](/workflows/push-and-pull). |
| Workflow | A function in your code, registered under a name that matches `^[A-Za-z0-9_-]{1,64}$`. A workflow runs only in the app that hosts it. |
| Run | One execution of a workflow, with a JSON input. It has a UUID `id` that EZGH assigns, and an optional `runKey` that you choose. |
| Step | A named unit of work inside a workflow: running a function, sleeping, recording a time or UUID, waiting for a callback, or running a child workflow. Each step's outcome is recorded once. |
| Invocation | One call of your workflow code by EZGH, as an HTTPS request to a push app or a task for a pull worker. A run takes several invocations. |
| Schedule | Starts runs of one workflow on a cron timetable. Its slug starts with `wfs_`. See [Schedules](/workflows/schedules). |

## How a run executes

1. **You start a run** with an SDK client or the [API](/workflows-api/StartRun/). EZGH
   records it and answers with the run, status `running`.
2. **EZGH invokes your code** with the run's input and the outcomes of the steps recorded so far.
3. **Your workflow function runs from the start.** Each step already recorded returns its
   recorded result at once, without running again. This is **replay**.
4. **At the first step that isn't recorded,** the SDK tells EZGH the step is starting, waits for
   the acknowledgement, runs it, and records its result. It continues with the next steps the same
   way.
5. **At a sleep, a callback wait, a child workflow or parallel steps,** the invocation ends. EZGH
   invokes your code again when there's something to continue with: the timer fires, the callback
   is completed, the child ends or the parallel steps finish.
6. **When the function returns,** the run ends `completed` with the return value as its output.
   When it throws an error, the run ends `failed`.

So a run continues after your process crashes, is redeployed or is down for a while: the next
invocation replays the recorded steps and carries on. A step whose result wasn't recorded before a
crash runs again, which is why [steps run at least once](/workflows/retries#idempotency).

## Run statuses

| Status | Meaning |
| --- | --- |
| `running` | The run is in progress, including while it sleeps or waits |
| `cancelling` | A cancel was requested; cleanup code may still run steps ([Cancellation](/workflows/cancellation)) |
| `completed` | The workflow returned; its output can be read |
| `failed` | The workflow threw an error, or EZGH couldn't invoke it; it can be [retried](/workflows/retrying-runs) |
| `cancelled` | The run was cancelled |
| `timedOut` | The run went past its time limit |

A run's `steps` list each step's name, kind, status and attempt. Step kinds are `run`, `sleep`,
`value` (`now` and `uuid`), `callback` and `invoke`. Step statuses are `running`, `retrying`,
`completed`, `failed`, `cancelled`, `sleeping` and `waiting`. The run's history,
[ListRunEvents](/workflows-api/ListRunEvents/), lists every invocation and step outcome
with the deployment that ran it. To find runs, [search them](/workflows/runs).

## Determinism

Because the workflow function runs again on every invocation, **code outside steps must take the
same path every time:**

- Put every side effect (an API call, a database write, an email) in a step.
- Read the time and random values through the `now` and `uuid` steps, not the clock or a random
  generator, so a replay sees the same values.
- Values that steps return are JSON. The SDK passes a result through JSON before your code sees
  it, so the first execution and every replay get the same value: in TypeScript a `Date` becomes
  a string and `undefined` becomes `null`.

Runs continue on whatever code is deployed. Each invocation records your **deployment ID**, which
the SDKs detect on Vercel, AWS Lambda, Cloud Run, Fly.io and Render, or which you set. Before you
change a workflow that has runs in progress, read how steps are identified in
[Steps and determinism](/workflows/steps).

## Run IDs and run keys

- **`id`** is a UUID that EZGH assigns. It's in every run URL and is never reused.
- **`runKey`** is optional and set when you start a run: `^[A-Za-z0-9._:-]{1,128}$`, unique in
  the project among runs that haven't been deleted yet. Starting a run with a key that exists
  answers the existing run (`200`) when the workflow and input are the same, and
  `409 run_key_conflict` when they aren't. Use it to make starts idempotent, for example
  `signup-<userId>`.

Runs started by a schedule or as a child workflow have IDs derived from their schedule or parent,
so they start exactly once, and no run key.

## Data and retention

- Inputs, outputs, step results and callback bodies are JSON, at most 1 MiB each.
- A run's data is deleted 30 days after it ends.
- A run can last up to a year.

Source: https://docs.ezghcloud.com/workflows/concepts/index.mdx
