Workflow Engine
Durable, step-based workflows with persistence and error recovery. Each step is checkpointed — if a workflow crashes, it resumes from the last completed step.
Setup
import "github.com/CodeSyncr/nimbus/workflow"
app.Use(workflow.NewPlugin())
// Dashboard at /workflows
Defining a Workflow
A workflow is a sequence of named steps. Each step is persisted — if the process crashes, it resumes from the last completed step on restart.
wf := workflow.Define("onboarding", func(ctx *workflow.Context) error {
// Step 1: Create account
err := ctx.Step("create_account", func() error {
return createAccount(ctx.Input)
})
if err != nil {
return err
}
// Step 2: Send welcome email
err = ctx.Step("send_email", func() error {
return sendWelcomeEmail(ctx.Input)
})
if err != nil {
return err
}
// Step 3: Setup defaults
err = ctx.Step("setup_defaults", func() error {
return setupUserDefaults(ctx.Input)
})
return err
})
Starting a Workflow
instance, err := workflow.Start("onboarding", map[string]any{
"email": "user@example.com",
"plan": "pro",
})
Features
| Feature | Description |
|---|---|
| Step Persistence | Each step is checkpointed; restart resumes from last completed step |
| Error Handling | Steps can fail and be retried independently |
| Dashboard | View workflow status at /workflows |
| Parallel Steps | Run independent steps concurrently |
| Timeouts | Set step-level and workflow-level timeouts |
Real-Life Example: Order Processing
wf := workflow.Define("process_order", func(ctx *workflow.Context) error {
orderID := ctx.Input["order_id"].(uint)
// Step 1: Verify payment (if this fails, order stops here)
err := ctx.Step("verify_payment", func() error {
return paymentService.Verify(orderID)
})
if err != nil {
return err
}
// Step 2: Reserve inventory
err = ctx.Step("reserve_inventory", func() error {
return inventoryService.Reserve(orderID)
})
if err != nil {
return err
}
// Step 3: Generate shipping label
err = ctx.Step("shipping_label", func() error {
return shippingService.CreateLabel(orderID)
})
if err != nil {
return err
}
// Step 4: Send confirmation
return ctx.Step("send_confirmation", func() error {
return notificationService.OrderConfirmed(orderID)
})
})
Best Practices
- Name steps descriptively — they appear in the dashboard and logs
- Keep each step idempotent — it may be retried on crash recovery
- Use workflows for multi-step business processes, not simple tasks
- Pass IDs in input, not full objects — workflow state is serialized
- Set timeouts on long-running steps to avoid stuck workflows