Hatchet Python V1 Migration Guide
This guide will help you migrate Hatchet workflows from the V0 SDK to the V1 SDK.
Introductory Example
First, a simple example of how to define a workflow with the V1 SDK:
The API has changed significantly in the V1 SDK. Even in this simple example, there are some notable highlights:
- Tasks can now be declared with
hatchet.task
, meaning you no longer have to create a workflow explicitly to define a task. This should feel similar to how e.g. Celery handles task definition. Note that we recommend declaring a workflow in many cases, but the simplest possible way to get set up is to usehatchet.task
. - Tasks have a new signature. They now take two arguments:
input
andcontext
. Theinput
is either of typeinput_validator
(a Pydantic model you provide to the workflow), or is anEmptyModel
, which is a helper Pydantic model Hatchet provides and uses as a default. Thecontext
is once again the HatchetContext
object. - Workflows can now be registered on a worker by using the
workflows
keyword argument to theworker
method, although the oldregister_workflows
method is still available.
Pydantic
Hatchet’s V1 SDK makes heavy use of Pydantic models, and recommends you do too! Let’s dive into a more involved example using Pydantic in a fanout example.
In this example, we use a few more new SDK features:
- Workflows are now declared with
hatchet.workflow
, and then have their corresponding tasks registered withworkflow.task
. - We define two Pydantic models,
ParentInput
andChildInput
, and pass them to the parent and child workflows asinput_validator
s. Note that now, theinput
parameters for the tasks in those two workflows are Pydantic models of those types, and we can treat them as such. This replaces the oldcontext.workflow_input
for accessing the input to the workflow / task - now, we just can access the input directly. - When we want to spawn the child workflow, we can use the
run
methods on thechild_workflow
object, which is a HatchetWorkflow
, instead of needing to refer to the workflow by its name (a string). Theinput
field torun()
is now also properly typed asChildInput
. - The child workflow (see below) makes use of some of Hatchet’s DAG features, such as defining parent tasks. In the new SDK,
parents
of a task are defined as a list ofTask
objects as opposed to as a list of strings, so now,process2
hasprocess
(theTask
) as its parent, as opposed to"process"
(the string). This also allows us to usectx.task_output(process)
to access the output of theprocess
task in theprocess2
task, and know the type of that output at type checking time.
See our Pydantic documentation for more.
Other Breaking Changes
There have been a number of other breaking changes throughout the SDK in V1.
Typing improvements:
- All times and durations, such as
timeout
andschedule_timeout
fields are nowdatetime.timedelta
objects instead of strings (e.g."10s"
becomestimedelta(seconds=10)
). - External-facing protobuf objects, such as
StickyStrategy
andConcurrencyLimitStrategy
, have been replaced by native Python enums to make working with them easier. - All interactions with the
Workflow
object are now typed, so you know e.g. what the type of the input to the workflow needs to be at type checking time (we see this in the Pydantic example above). - All external-facing types that are used for triggering workflows, scheduling workflows, etc. are now Pydantic objects, as opposed to being
TypedDict
s. - The return type of each
Task
is restricted to aJSONSerializableMapping
or a Pydantic model, to better align with what the Hatchet Engine expects. - The
ClientConfig
now uses Pydantic Settings, and we’ve removed the static methods on the Client forfrom_environment
andfrom_config
in favor of passing configuration in correctly. See the configuration example for more details. - The REST API wrappers, which previously were under
hatchet.rest
, have been completely overhauled.
Naming changes:
- We no longer have nested
aio
clients for async methods. Instead, async methods throughout the entire SDK are prefixed byaio_
, similar to Langchain’s use of thea
prefix to indicate async. For example, to run a workflow, you may now either useworkflow.run()
orworkflow.aio_run()
. - All functions on Hatchet clients are now verbs. For instance the way to list workflow runs is via
hatchet.workflows.list
. max_runs
on the worker has been renamed toslots
.
Removals:
sync_to_async
has been removed. We recommend reading our asyncio documentation for our recommendations on handling blocking work in otherwise async tasks.
Other miscellaneous changes:
- As shown in the Pydantic example above, there is no longer a
spawn_workflow(s)
method on theContext
.run
is now the preferred method for spawning workflows, which will automatically propagate the parent’s metadata to the child workflow.
Other New features
There are a handful of other new features that will make interfacing with the SDK easier, which are listed below.
- Concurrency keys using the
input
to a workflow are now checked for validity at runtime. If the workflow’sinput_validator
does not contain a field that’s used in a key, Hatchet will reject the workflow when it’s created. For example, if the key isinput.user_id
, theinput_validator
Pydantic model must contain auser_id
field. - There is now an
on_success_task
on theWorkflow
object, which works just like an on-failure task, but it runs after all upstream tasks in the workflow have succeeded.