Workflow ServicePreview
Overview
Workflow service enables you to build and execute complex, multi-step background jobs with automatic state management and resume capabilities on Tailor Platform.
If a workflow fails at any step, you can resume it from where it stopped without re-executing successful steps, making it ideal for long-running operations that need reliability.
With Workflow service, you can:
- Chain multiple JavaScript functions into durable workflows
- Automatically preserve execution state at each step
- Resume failed workflows from the point of failure
- Access TailorDB and other platform services with proper authentication
- Monitor execution progress through Tailor Console and tailorctl CLI
Workflow vs Function
Both Workflow and Function services execute JavaScript code, but serve different purposes:
| Feature | Function | Workflow |
|---|---|---|
| Execution model | Synchronous, single execution | Multi-step, stateful execution |
| Duration | Short-lived (seconds) | Long-running (minutes to hours) |
| State management | None | Automatic state preservation |
| Resume capability | No | Yes, from point of failure |
| Use case | Data transformation, API calls | Complex background jobs, multi-step processes |
| Called from | Pipeline resolvers, Executors | Executors, Functions |
When to use Workflow:
- You need to chain multiple operations with state preservation
- The job may fail and needs to be resumed without repeating successful steps
- You're orchestrating complex business processes across multiple services
When to use Function:
- You need quick, synchronous data processing
- The operation is a single, atomic task
- You're transforming data within Pipeline resolvers
How Workflow Execution Works
Durable Execution Model
Workflow service uses a durable execution model where the execution state is automatically saved after each successful step.
Example execution flow:
Step 1: Fetch data from API → Success ✓ (result cached)
Step 2: Transform data → Success ✓ (result cached)
Step 3: Save to database → Failed ✗
When you resume the workflow:
Step 1: Fetch data from API → Skipped (use cached result)
Step 2: Transform data → Skipped (use cached result)
Step 3: Save to database → Retry from here
Benefits:
- No duplicate work: Successful steps are never re-executed
- Safe retries: You can retry as many times as needed
- Cost efficient: Only failed steps consume resources on retry
- Data consistency: Results from successful steps remain available
Stack-Based Execution
Workflows support nested function calls, similar to regular programming:
<span><span style="color: var(--shiki-token-keyword)">export</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">function</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">main</span><span style="color: var(--shiki-color-text)">(args) {</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-comment)">// Call functions sequentially</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">data</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">tailor</span><span style="color: var(--shiki-token-function)">.</span><span style="color: var(--shiki-token-constant)">workflow</span><span style="color: var(--shiki-token-function)">.triggerJobFunction</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">"fetchData"</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> {});</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">processed</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">tailor</span><span style="color: var(--shiki-token-function)">.</span><span style="color: var(--shiki-token-constant)">workflow</span><span style="color: var(--shiki-token-function)">.triggerJobFunction</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">"processData"</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> data);</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">return</span><span style="color: var(--shiki-color-text)"> processed;</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>
The execution stack:
[] → [main] → [main, fetchData] → [main] → [main, processData] → [main] → []
Each function's result is cached and passed to the next function in the chain.
Job functions within a single workflow execute sequentially, not in parallel. Each function completes before the next one starts. For concurrent execution, you can start multiple workflows asynchronously using tailor.workflow.triggerWorkflow().