Skip to content

Steps

Durable steps that survive crashes. Each step's result is saved — if the process crashes mid-workflow, it resumes from the last completed step without re-executing it.

What to notice:

  • Each turbine.Do call is a checkpoint — its result is recorded in SQLite
  • Steps receive context.Context, not turbine.Context — this prevents nesting steps
  • On recovery, completed steps replay their saved result instead of re-executing
go
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/YakirOren/turbine"
	"github.com/pocketbase/pocketbase"
	"github.com/pocketbase/pocketbase/core"
)

func ChargePayment(ctx context.Context) (string, error) {
	// call payment provider
	return "charge_ok", nil
}

func FulfillOrder(ctx context.Context) (bool, error) {
	// ship the order
	return true, nil
}

// OrderWorkflow demonstrates durable steps.
// Each step's result is saved — if the process crashes mid-workflow,
// it resumes from the last completed step without re-executing it.
func OrderWorkflow(ctx turbine.Context, orderID string) (string, error) {
	chargeID, err := turbine.Do(ctx, ChargePayment, turbine.WithStepName("charge"))
	if err != nil {
		return "", err
	}

	_, err = turbine.Do(ctx, FulfillOrder, turbine.WithStepName("fulfill"))
	if err != nil {
		return "", err
	}

	return fmt.Sprintf("order %s completed (charge: %s)", orderID, chargeID), nil
}

func main() {
	app := pocketbase.New()

	rt := turbine.Setup(app, turbine.Config{})

	turbine.Register(rt, OrderWorkflow)

	app.OnServe().BindFunc(func(e *core.ServeEvent) error {
		e.Router.POST("/order/{id}", func(re *core.RequestEvent) error {
			id := re.Request.PathValue("id")

			handle, err := turbine.Run(rt, OrderWorkflow, id)
			if err != nil {
				return re.JSON(500, map[string]string{"error": err.Error()})
			}

			result, err := handle.GetResult()
			if err != nil {
				return re.JSON(500, map[string]string{"error": err.Error()})
			}

			return re.JSON(200, map[string]string{"result": result})
		})
		return e.Next()
	})

	if err := app.Start(); err != nil {
		log.Fatal(err)
	}
}