Workflow
Workflow runs durable server-side processes that can outlive a single request. Workflow fits work that needs retries, pauses, checkpoints, or a run id that you can inspect again later.
ViteHub discovers workflows from server/workflows/**.
Define a workflow with createWorkflow(options?)(handler) or defineWorkflow(handler, options?), then start runs with runWorkflow() and reattach with getWorkflowRun().
Getting started
Install the package
pnpm add https://pkg.pr.new/nuxt-hub/agent/@vitehub/workflow@main
pnpm add https://pkg.pr.new/nuxt-hub/agent/@vitehub/workflow@main workflow
pnpm add https://pkg.pr.new/nuxt-hub/agent/@vitehub/workflow@main openworkflow
Configure a provider
workflow.provider selects the workflow provider. Cloudflare and Vercel are inferred from hosted presets, so set it only for OpenWorkflow or when you want to override the inferred provider. On Cloudflare, workflow.binding is only needed when you want to override the default binding or pass a binding-like object.
export default defineNuxtConfig({
modules: ['@vitehub/workflow/nuxt'],
})
export default defineNuxtConfig({
modules: ['@vitehub/workflow/nuxt'],
})
export default defineNuxtConfig({
modules: ['@vitehub/workflow/nuxt'],
workflow: {
provider: 'openworkflow',
},
})
Define a workflow
Create a workflow in server/workflows/**. The file name becomes the workflow name.
import { createWorkflow } from '@vitehub/workflow'
export default createWorkflow()(async (input?: { title?: string }) => {
const title = input?.title?.trim() || 'Untitled draft'
return {
title,
slug: title.toLowerCase().replace(/[^a-z0-9]+/g, '-'),
}
})
Start a run
import { readBody } from 'h3'
import { runWorkflow } from '@vitehub/workflow'
export default defineEventHandler(async (event) => {
const body = await readBody<{ title?: string }>(event)
const run = await runWorkflow('publish-draft', {
title: body.title,
})
return {
runId: run.id,
status: await run.status(),
}
})
Reattach to the same run later
Persist or return the run id when you start a workflow. Use it later to check status or call provider-specific run methods.
import { getRouterParam } from 'h3'
import { getWorkflowRun } from '@vitehub/workflow'
export default defineEventHandler(async (event) => {
const run = await getWorkflowRun(getRouterParam(event, 'id'))
if (!run)
return { found: false }
return {
found: true,
status: await run.status(),
}
})
Public API
| Function | Use it for |
|---|
| createWorkflow(options?)(handler) | Register one named workflow under server/workflows/**. |
| defineWorkflow(handler, options?) | Compatibility wrapper for createWorkflow(options?)(handler). |
| runWorkflow(name, payload) | Start a new workflow run and get a run handle back immediately. |
| getWorkflowRun(runId) | Reattach to an existing run from a later request, task, or webhook. |
Type reference
Handler signature
The handler receives an optional input and returns the workflow result. ViteHub does not enforce a return type.
type WorkflowHandler<TInput, TResult> = (
input?: TInput,
) => TResult | Promise<TResult>
WorkflowDefinitionOptions
The options object passed to createWorkflow() or the second argument to defineWorkflow() accepts:
| Option | Type | Description |
|---|---|---|
timeout | number | Maximum execution time in milliseconds. |
WorkflowRun
runWorkflow() returns a WorkflowRun handle with:
| Field / Method | Type | Description |
|---|---|---|
id | string | Unique run identifier. Persist this to reattach later. |
provider | string | The active provider name. |
native | object | Raw provider-native run object. |
status() | Promise<WorkflowRunStatus> | Poll the current run state. |
stop() | Promise<void> | Cancel the run. |
WorkflowRunStatus
| Field | Type | Description |
|---|---|---|
state | 'queued' | 'running' | 'paused' | 'waiting' | 'completed' | 'failed' | 'cancelled' | 'terminated' | 'unknown' | Current run state. |
raw | unknown | Raw provider response. |
output | unknown | Handler return value when the run completes. |
error | unknown | Error details when the run fails. |
How configuration works
Workflow has one global layer and one definition layer:
- Top-level
workflowconfig innuxt.config.tsornitro.config.tsselects the provider and sets up the app-wide integration. createWorkflow(options?)(handler)configures one workflow definition with portable options such astimeout.defineWorkflow(handler, options?)remains available as a compatibility wrapper.
runWorkflow() starts a new run with input for that specific execution. getWorkflowRun() reconnects to an existing run by id. Neither one replaces top-level or definition-level configuration.
export default defineNuxtConfig({
modules: ['@vitehub/workflow/nuxt'],
workflow: {
provider: 'cloudflare',
},
})
export default createWorkflow()(async (input) => {
return input
})
workflow, and OpenWorkflow needs openworkflow.