Skip to content

Quickstart: Go

Install the Go SDK from GitHub, run a pull worker on your machine, and start a run.

Updated View as Markdown

This quickstart runs a workflow on your own machine: you create a pull app, run a worker that polls EZGH for work, and start a run. Nothing needs a public endpoint. It takes about five minutes.

Before you start

  • Go 1.26 or later.
  • The ezgh CLI, version 0.16.0 or later (install it, or run ezgh update), logged in.
  • An organization ID and a project ID. Run ezgh whoami for the organization and ezgh projects list for the project, or copy them from the console. The SDKs take IDs, not slugs.
  • An API key whose owner has WorkflowsFullAccess on the project, or the root user’s. Create one with ezgh iam api-keys create workflows-quickstart.

Set them in your shell:

export EZGH_API_KEY=ezgh_…
export EZGH_ORG_ID=<org-id>
export EZGH_PROJECT_ID=<project-id>

1. Create a pull app

ezgh workflows apps create quickstart --kind pull --project "$EZGH_PROJECT_ID"

The output shows the app. Keep its ID:

export EZGH_APP_ID=<ID>

2. Install the SDK

Install it by tag:

mkdir workflows-quickstart && cd workflows-quickstart
go mod init example.com/quickstart
go get github.com/ezgamehost/workflows-sdk-go@v0.1.0

It uses only the Go standard library.

3. Write a workflow and a worker

main.go defines a workflow named hello with three steps: it computes a greeting, sleeps for five seconds, and records the time. Run without arguments, the program is a worker that polls the app’s task queue and runs the workflow; each poll also tells EZGH which workflows this worker serves. Run with start, it starts a run, checks it every second until it ends, and prints its output.

main.gogo
package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"os/signal"
	"time"

	workflows "github.com/ezgamehost/workflows-sdk-go"
)

type Input struct {
	Name string `json:"name"`
}

type Output struct {
	Greeting string    `json:"greeting"`
	At       time.Time `json:"at"`
}

var hello = workflows.New("hello", func(ctx workflows.Context, in Input) (Output, error) {
	greeting, err := workflows.Run(ctx, "greet", func(sc workflows.StepContext) (string, error) {
		return "Hello, " + in.Name + "!", nil
	})
	if err != nil {
		return Output{}, err
	}
	if err := workflows.Sleep(ctx, "pause", 5*time.Second); err != nil {
		return Output{}, err
	}
	at, err := workflows.Now(ctx, "finished-at")
	if err != nil {
		return Output{}, err
	}
	return Output{Greeting: greeting, At: at}, nil
})

func main() {
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
	defer stop()
	if len(os.Args) > 1 && os.Args[1] == "start" {
		start(ctx)
		return
	}
	w, err := workflows.NewWorker(workflows.WorkerOptions{
		APIKey:         os.Getenv("EZGH_API_KEY"),
		OrganizationID: os.Getenv("EZGH_ORG_ID"),
		ProjectID:      os.Getenv("EZGH_PROJECT_ID"),
		App:            os.Getenv("EZGH_APP_ID"),
		Workflows:      []workflows.Workflow{hello},
	})
	if err != nil {
		log.Fatal(err)
	}
	log.Print("Worker polling. Press Ctrl+C to stop.")
	if err := w.Run(ctx); err != nil {
		log.Fatal(err)
	}
}

func start(ctx context.Context) {
	c, err := workflows.NewClient(workflows.ClientOptions{
		APIKey:         os.Getenv("EZGH_API_KEY"),
		OrganizationID: os.Getenv("EZGH_ORG_ID"),
		ProjectID:      os.Getenv("EZGH_PROJECT_ID"),
	})
	if err != nil {
		log.Fatal(err)
	}
	run, err := c.Start(ctx, os.Getenv("EZGH_APP_ID"), "hello", Input{Name: "Ada"}, workflows.StartOptions{})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Started run", run.ID)
	for !run.Terminal() {
		time.Sleep(time.Second)
		if run, err = c.Get(ctx, run.ID); err != nil {
			log.Fatal(err)
		}
	}
	var out Output
	if run.Status == workflows.RunStatusCompleted {
		if err := c.Output(ctx, run.ID, &out); err != nil {
			log.Fatal(err)
		}
	}
	fmt.Println(run.Status, out.Greeting, out.At)
}

4. Run the worker

go run .

Leave it running.

5. Start a run

In a second terminal with the same environment variables:

go run . start

After about five seconds:

Started run 0d415599-27ed-80a5-8ac6-9eb1cd742b40
completed Hello, Ada! 2026-10-11 20:30:16.879 +0000 UTC

The worker ran the workflow twice: once up to the sleep, and again after it, when the greet step returned its recorded result without running again.

A pull app starts runs only of workflows that one of its workers announced in the last 10 minutes. Starting a run with no worker running answers 409 workflow_not_announced.

6. Clean up

Stop the worker with Ctrl+C, then delete the app and, if you made one for this, the API key:

ezgh workflows apps delete quickstart --project "$EZGH_PROJECT_ID"
unset EZGH_API_KEY
ezgh iam api-keys delete workflows-quickstart

Next

Navigation

Type to search…

↑↓ navigate↵ selectEsc close