Workflow Configuration
To create a workflow, simply create a new Workflow
object. For example, a simple 2-step workflow would look like:
import Hatchet, { Workflow } from "@hatchet-dev/typescript-sdk";
const hatchet = Hatchet.init();
const workflow: Workflow = {
id: "example",
description: "test",
on: {
event: "user:create",
},
steps: [
{
name: "step1",
run: (ctx) => {
console.log("executed step1!");
return { step1: "step1" };
},
},
{
name: "step2",
parents: ["step1"],
run: (ctx) => {
console.log("executed step2!");
return { step2: "step2" };
},
},
],
};
You'll notice that the workflow defines a workflow trigger (in this case, on the event user:create
), and the workflow definition. The workflow definition includes a series of steps which is simply an array of Step
objects.
Each step has a run
prop which is a function that with a context
augment. The context
argument is a Context
object, which contains information about the workflow, such as the input data and the output data of previous steps.
To create multi-step workflows, you can use parents
to define the steps which the current step depends on. In the example, step2
will not invoke until after step1
completes.
Retrieving Workflow Input Data
You can get access to the workflow's input data, such as the event data or other specified input data, by using the ctx.workflowInput()
method on the context
argument, which is the first argument to the step function. It's also recommended that you typecast this to the Context<T>
type, where T
is the type of the input data. For example:
type MyType = {
name: string;
};
const stepPrintsInput: Step = {
name: "step2",
parents: ["step1"],
run: (ctx: Context<MyType>) => {
console.log("executed step2!", ctx.workflowInput().name);
},
};
Step Outputs
Step outputs should be a of type Record<string, any>
, should be JSON
serializable, and are optional. For example:
const stepReturnsData: Step = {
name: "step2",
run: (ctx) => {
return { awesome: "data" };
},
};
Future steps can access this output through the context (ctx
) parameter ctx.stepOutput("<step_name>")
. In this example, a future step could access this data via context.stepOutput("step2")
:
const futureStep: Step = {
name: "step3",
run: (ctx) => {
const uppercaseStep2 = ctx.stepOutput("step2")["awesome"].toUpperCase();
return { uppercase: uppercaseStep2 };
},
};
Remember, a step that depends on previous step data should include this dependency in the parents
array.
Timeouts
The default timeout on Hatchet is 60 seconds per step run.
You can declare a timeout for a step by passing timeout
to the Step
definition. Timeouts are strings in the format of 1h
, 1m
, 1s
, etc. For example, to timeout a step after 5 minutes, you can do the following:
const stepWithTimeout: Step = {
name: "step2",
run: (ctx) => {
console.log("executed step2!");
return { step2: "step2" };
},
timeout: "5m",
};
Cancellations
When a step is running and needs to be cancelled, Hatchet will send a cancellation signal to the step via it's context. This cancellation signal can be retrieved via ctx.controller.signal
which returns an AbortController
(opens in a new tab), and is used by many HTTP libraries to cancel active requests. You can also case on the signal.aborted
property to check if the step has been cancelled. For example:
{
"step1",
run: async (ctx) => {
const { data } = ctx.workflowInput();
const { signal } = ctx.controller;
if (signal.aborted) throw new Error("step1 was aborted");
console.log("starting step1 and waiting 5 seconds...", data);
await sleep(5000);
if (signal.aborted) throw new Error("step1 was aborted");
// NOTE: the AbortController signal can be passed to many http libraries to cancel active requests
// fetch(url, { signal })
// axios.get(url, { signal })
console.log("executed step1!");
return { step1: `step1 results for ${data}!` };
},
},