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.Docall is a checkpoint — its result is recorded in SQLite - Steps receive
context.Context, notturbine.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)
}
}