2.0 KiB
2.0 KiB
title, impact, impactDescription, tags
| title | impact | impactDescription | tags |
|---|---|---|---|
| Follow Workflow Constraints | CRITICAL | Violating constraints breaks recovery and durability guarantees | workflow, constraints, rules, best-practices |
Follow Workflow Constraints
Workflows have specific constraints to maintain durability guarantees. Violating them can break recovery.
Incorrect (starting workflows from steps):
func myStep(ctx context.Context) (string, error) {
// Don't start workflows from steps!
// The step's context.Context does not support workflow operations
return "", nil
}
func myWorkflow(ctx dbos.DBOSContext, input string) (string, error) {
// Starting a child workflow inside a step breaks determinism
dbos.RunAsStep(ctx, func(ctx context.Context) (string, error) {
handle, _ := dbos.RunWorkflow(ctx.(dbos.DBOSContext), otherWorkflow, "data") // WRONG
return handle.GetWorkflowID(), nil
})
return "", nil
}
Correct (workflow operations only from workflows):
func fetchData(ctx context.Context) (string, error) {
// Steps only do external operations
resp, err := http.Get("https://api.example.com")
if err != nil {
return "", err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
return string(body), nil
}
func myWorkflow(ctx dbos.DBOSContext, input string) (string, error) {
data, err := dbos.RunAsStep(ctx, fetchData, dbos.WithStepName("fetchData"))
if err != nil {
return "", err
}
// Start child workflows from the parent workflow
handle, err := dbos.RunWorkflow(ctx, otherWorkflow, data)
if err != nil {
return "", err
}
// Receive messages from the workflow
msg, err := dbos.Recvstring
// Set events from the workflow
dbos.SetEvent(ctx, "status", "done")
return data, nil
}
Additional constraints:
- Don't modify global variables from workflows or steps
- All workflows and queues must be registered before
Launch() - Concurrent steps must start in deterministic order using
dbos.Go/dbos.Select
Reference: Workflow Guarantees