A durable countdown: register a function, invoke it from the CLI, and watch it tick down — surviving restarts along the way. This is the Go side of the cross-language quickstart.
resonate-sdk-gois pre-release. The SDK has no semver tag yet, so this example pins to a specific commit. Expect API changes untilv0.1.0.
A countdown as a loop — plain Go, a for that prints each tick and sleeps between them. What makes it durable is that the loop can run for minutes, hours, or days, and resume exactly where it left off if the worker process dies and comes back.
- Registering a Go function as a named, durable workflow with
resonate.Register. - Persisting each step with
ctx.Runand suspending between ticks withctx.Sleep— both durable across crashes. - Invoking a registered function by name from the Resonate CLI with
resonate invoke.
These primitives are the foundation every Resonate program is built on, from a simple countdown to distributed sagas and durable sleep.
func countdown(ctx *resonate.Context, args []int) (struct{}, error) {
count, delay := args[0], args[1]
for i := count; i > 0; i-- {
// Run a function, persist its result
f, _ := ctx.Run(notify, i)
f.Await(nil)
// Sleep
s, _ := ctx.Sleep(time.Duration(delay) * time.Second)
s.Await(nil)
}
fmt.Println("Done!")
return struct{}{}, nil
}
func notify(i int) (struct{}, error) {
fmt.Printf("Countdown: %d\n", i)
return struct{}{}, nil
}
func main() {
r, _ := resonate.New(resonate.Config{URL: "http://localhost:8001"})
resonate.Register(r, "countdown", countdown)
// ... keep the worker alive to receive CLI-invoked work
}Two things worth knowing:
- The workflow's args arrive as a
[]intslice — the CLI passes each--argas one element of a JSON array, so--arg 5 --arg 60becomesargs[0]=5, args[1]=60. notifyis wrapped inctx.Runso its result is recorded in a durable promise. On resume after a crash, already-printed ticks short-circuit instead of re-printing.
Every iteration of the loop creates two durable promises — one for the ctx.Run step, one for the ctx.Sleep. While the countdown is running, inspect them with resonate tree:
resonate tree countdown.1countdown.1
├── countdown.1.1 🟢 (run)
└── countdown.1.2 🟡 (sleep)
countdown.1 is the root invocation. countdown.1.1 is the resolved notify run; countdown.1.2 is the sleep still in progress. Kill the worker now and the green promise stays resolved — Resonate never re-runs work it has already recorded, so the countdown resumes from the pending sleep rather than starting over.
- Go 1.22+
- The Resonate CLI (it ships the dev server and the
invokecommand):
brew install resonatehq/tap/resonatePrefer a prebuilt binary? Download one from the releases page.
git clone https://github.com/resonatehq-examples/example-quickstart-go.git
cd example-quickstart-go
go mod downloadStart the server:
resonate devStart the worker (it registers countdown and waits for work):
go run .Invoke the function with execution ID countdown.1:
resonate invoke countdown.1 --func countdown --arg 5 --arg 60Expected worker output:
Countdown: 5
Countdown: 4
Countdown: 3
Countdown: 2
Countdown: 1
Done!
Once the countdown is working, here are natural next steps in rough order of complexity:
- Crash resilience — invoke with a long delay (
--arg 5 --arg 60), kill the worker mid-countdown with Ctrl-C, then restart it. Resonate resumes the surviving promise where it stopped rather than starting over. - Durable sleep — the
ctx.Sleephere can suspend for hours, days, or weeks. Seeexample-durable-sleep-go. - Recursive workflows — a factorial example that fans out sub-invocations. See
example-recursive-factorial-go. - How Resonate works — https://docs.resonatehq.io/evaluate/how-it-works
- Go SDK docs — https://docs.resonatehq.io/develop/go
example-quickstart-go/
├── main.go program entry point
├── go.mod module declaration + SDK pin
├── go.sum checksums
├── LICENSE Apache-2.0
└── README.md
- Discord: https://resonatehq.io/discord
- X: https://x.com/resonatehqio
- LinkedIn: https://www.linkedin.com/company/resonatehqio
- YouTube: https://www.youtube.com/@resonatehqio
- Journal: https://journal.resonatehq.io