Why Steps Are Needed
Without Steps in a Workflow, if something fails midway, you have to restart from the beginning. With Steps, you can resume from where it failed.- Partial Retry: Re-execute only from the failed step
- Progress Tracking: Check execution time and status of each step
- Easier Debugging: Clearly identify which step failed
step.define()
step.define() is the most basic way to wrap a function as a step. When you make an async function a step, its execution history is saved to the database.
name: Step identifier (must be unique within the workflow)- Async function: Code that performs the actual work
.run(): Executes the step and returns the result
Using Return Values
You can use the return value of a Step in subsequent steps. Each step is saved independently, but data is passed in memory.fetch_datastep returns data- data is passed in memory to
transformstep - transformed is passed in memory to
savestep
When a Step is retried, previous step results are restored from the database.
step.get()
step.get() is a convenient way to execute a Model method as a step. You donβt need to wrap the function separately, making the code more concise.
- Reuse Model business logic
- Eliminate code duplication
- Maintain type safety
Custom Name
You can explicitly specify a Step name to make logs more readable.Using Return Values
Model method return values work the same way.step.sleep()
step.sleep() is a step that waits for a specified duration. Use it for delays between retries, avoiding API rate limits, periodic polling, and more.
Practical Uses:
- Retry delay: Wait 5 seconds after failure
- Rate limiting: Wait 1 second between API calls
- Batch interval: Rest 10 seconds after processing 100 items
Practical Examples
1. Batch Processing
When processing large amounts of data, divide into smaller batches. Making each batch a separate step means already processed batches wonβt be re-run on failure.- Process in batches of 100
- Each batch is an independent step
- Progress logged
2. External API Calls
External API calls can fail due to network issues. With Steps, you can retry only the failed API call.- On API call failure, skip data normalization
- On normalization failure, donβt re-call the API
- Can measure execution time for each stage
3. File Processing Pipeline
A pipeline that downloads a file, parses it, and saves it. Dividing each stage into steps makes debugging and retrying easier.- Download -> 2. Parse -> 3. Validate -> 4. Save
- On failure, retry from that step
- File is downloaded only once
4. API with Rate Limiting
When an API has rate limits, add delays between requests. Usingstep.sleep() prevents the delay from repeating on retry.
- Wait 100ms between each notification
- Prevent API server overload
- On retry, skip already successful notifications
Step Naming Conventions
Use Unique Names
Step names must be unique within the same workflow. Using duplicate names will only execute the last step.Dynamic Names in Loops
When creating steps in loops, include the index to make names unique.- Use nouns describing the task:
fetch_user,send_email - Include index:
process_batch_0,process_batch_1 - Snake case recommended:
send_welcome_email
Important Notes
Next Steps
@workflow Decorator
Define and schedule workflows
Error Handling
Learn retry patterns and compensating transactions