Starting and Reading Runs
Clients
Code outside a run uses a Client to start, read, cancel, and resume runs. The workflow package functions find the Client in the context.
| Constructor | Use when |
|---|---|
workflow.NewClient(world) | The World is open in the same process. |
workflow.NewHTTPClient(endpoint) | The World is served by its HTTP handler in another process. |
Put a Client in a context with workflow.NewContext, or in every request context of an HTTP server with workflow.Middleware:
ctx = workflow.NewContext(ctx, workflow.NewClient(world))client := workflow.NewHTTPClient("http://workflow-worker:8081/v1/workflow")
log.Fatal(http.ListenAndServe(":8080", workflow.Middleware(mux, client)))NewHTTPClient takes an absolute URL and panics on anything else. It uses http.DefaultClient unless you pass your own *http.Client, for example one that adds authentication:
client := workflow.NewHTTPClient(endpoint, &http.Client{Transport: authTransport})The endpoint is the URL prefix the World's handler serves, including /v1/workflow. The client posts to <endpoint>/rpc, so for a worker serving HTTP(world) at the root of port 8081, the endpoint is http://workflow-worker:8081/v1/workflow.
Starting a run
workflow.Start starts a run of a workflow and returns a handle without waiting. It needs only the workflow type.
run, err := workflow.Start(ctx, workflows.GenerateReport{Topic: "workflows"})
if err != nil {
return err
}
fmt.Println(run.ID())It returns workflow.ErrNoClient when the context has no Client and does not belong to a run. In workflow context, Start starts a child run.
Getting an existing run
workflow.Get returns a handle to a run by ID. The type parameter is the workflow's output type. Get does not check that the run exists. Call run.Exists to check it.
run, err := workflow.Get[workflows.GenerateReportResult](ctx, runID)The Run handle
| Method | Description |
|---|---|
ID | Run ID. |
Value | Output once the run finishes. Blocks outside workflow context until it finishes or ctx is done. |
Status | Current Status. |
Exists | Whether the run is recorded in its World. |
WorkflowName | Name of the workflow the run executes. |
Cancel | Cancels the run. No-op if it already finished. |
WakeUp | Settles pending timers early. See Sleep and Timers. |
Reader | Reads a stream from a chunk index. See Streams. |
Writer | Writes a stream from outside the run. |
Value returns a failed run's error as a *workflow.Error and a cancelled run's as workflow.ErrRunCancelled. Status and WorkflowName return worlds.ErrRunNotFound for a missing run.
Statuses
| Status | Meaning |
|---|---|
workflow.StatusPending | Recorded but not started. |
workflow.StatusRunning | Started and not finished. |
workflow.StatusCompleted | Finished with an output. |
workflow.StatusFailed | Finished with an error. |
workflow.StatusCancelled | Cancelled before it finished. |
Steps use the same statuses except for cancelled. A cancelled step records a fatal failure.
In workflow context
Inside a runner, methods that read or change the run use inline steps, and replay returns the recorded result. They never wait: Value returns workflow.ErrRunNotFinished for a run that hadn't finished. WakeUp records which waits it will wake in one inline step before waking them in another, so a retry never wakes a timer the other run created later. The exceptions are Reader and Writer, which are I/O and return workflow.ErrNotInStep there. Use them in a step.
Cancelling a run
Run.Cancel stops new work and leaves already-running steps to finish. Reading a cancelled run returns workflow.ErrRunCancelled. A managed context passed to Start does not control the run's lifetime. See Cancellation for examples and step cancellation behavior.
Resuming hooks
workflow.ResumeHook, ResumeHookWithRetries, and GetHook also use the Client in the context. See Hooks.
Lower-level access
workflow.Client is an alias of worlds.Client, which exposes the full API: listing runs and steps, setting attributes, reading streams by cursor, and analytics. See the worlds reference.
client := workflow.NewClient(world)
page, err := client.RunsList(ctx, worlds.RunsListInput{})