Skip to main content

ORCHER Python SDK

Crash-proof workflows, written as plain async Python.


PyPI Python versions CI Apache 2.0

Write async functions; ORCHER journals each step and resumes interrupted runs where they stopped.

  • Durable: every step journaled; crashed runs resume on another worker
  • Plain Python: @workflow and @task on async functions, no DSL
  • Deterministic replay: step ids, time and randomness stay the same on every replay
  • Smart retries: per-task policies and never-retry error types
  • Timers and events: sleep for days or wait for an outside event
  • Child workflows: compose and run workflows in parallel
  • Actors: stateful objects with a single writer per key
  • Testing: run workflows in memory with mocks and a fake clock
  • Multi-tenant: API keys, organizations and namespaces built in
  • Native core: the engine protocol and state machine run in Rust

Install

pip install orcher-sdk

The package installs as orcher:

import orcher

Quick start

Decorate a task and a workflow that calls it. Both register themselves when their module is imported, and the worker runs everything registered:

import asyncio
import os

from orcher import TaskContext, Worker, WorkflowContext, task, workflow


@task(name="send-confirmation", retry=3)
async def send_confirmation(ctx: TaskContext, order_id: str, email: str) -> str:
    return f"sent confirmation for {order_id} to {email}"


@workflow(name="confirm-order")
async def confirm_order(ctx: WorkflowContext, order_id: str, email: str) -> str:
    return await ctx.execute_task(send_confirmation, order_id=order_id, email=email)


async def main() -> None:
    worker = (
        Worker.builder()
        .server_url("http://localhost:50051")
        .namespace("default")
        .task_queue("orders")
        .api_key(os.environ.get("ORCHER_API_KEY"))  # for an engine that requires one
        .build()
    )
    await worker.run()


if __name__ == "__main__":
    asyncio.run(main())

Tasks that need clients or connections can be methods of a @tasks class instead; hand the worker a built instance with worker.register_task_instance().

Start it from any process and wait for the result. A dict input reaches the workflow as keyword arguments:

import os

from orcher import Client, ClientConfig

config = ClientConfig(
    server_url="http://localhost:50051",
    api_key=os.environ.get("ORCHER_API_KEY"),  # for an engine that requires one
)
async with Client(config) as client:
    handle = await client.start_workflow(
        "confirm-order",
        task_queue="orders",
        args=({"order_id": "order-1", "email": "ada@example.com"},),
    )
    receipt = await handle.result()

Guide

Timers: sleep for minutes or months

A timer is recorded by the engine, so no worker is busy while it runs, and a restart doesn't reset it:

from datetime import timedelta

from orcher import WorkflowContext, workflow


@workflow(name="trial")
async def trial(ctx: WorkflowContext, email: str) -> None:
    await ctx.sleep(timedelta(days=14))
    await ctx.execute_task(send_trial_ended, email=email)
Events: wait for something outside the workflow

A workflow can park until a named event arrives, optionally with a deadline:

from datetime import timedelta

from orcher import WorkflowContext, workflow


@workflow(name="approval")
async def approval(ctx: WorkflowContext, request_id: str) -> str:
    try:
        approved = await ctx.wait_for_event_with_timeout("approved", timedelta(days=3))
    except TimeoutError:
        return f"{request_id} expired"
    return f"{request_id} approved" if approved else f"{request_id} rejected"

Send the event from a client:

handle = await client.get_workflow("approval-42")
await handle.send_event("approved", True)
Child workflows: compose workflows from workflows
from orcher import WorkflowContext, workflow


@workflow(name="ship-order")
async def ship_order(ctx: WorkflowContext, order_id: str) -> str:
    label = await ctx.execute_child_workflow("print-label", args=(order_id,))
    return f"{order_id} shipped with {label}"

ctx.start_child_workflow() returns a handle instead, to run several children at once and collect their results later.

Retries: decide which failures are worth retrying

A failure's type is the exception's class name (CardDeclined, not payments.CardDeclined). List the types never to retry in the task's policy. An exception whose non_retryable attribute is true is never retried, whatever the policy allows:

from orcher import RetryPolicy, TaskContext, task


class CardDeclined(Exception):
    pass


class AccountClosed(Exception):
    non_retryable = True


@task(
    name="charge",
    retry_policy=RetryPolicy(max_attempts=5, non_retryable_error_types=["CardDeclined"]),
)
async def charge(ctx: TaskContext, order_id: str) -> str:
    # Runs once:
    raise CardDeclined(f"card declined for {order_id}")
    # Also runs once, listed or not:
    # raise AccountClosed(f"account closed for {order_id}")

Any other exception is retried. non_retryable can also be set on a single instance before it is raised.

Time and randomness: the replay-safe way

ctx.time reads the time the engine recorded, and ctx.random is seeded from the run, so both give the same answer every time the workflow is replayed:

from orcher import WorkflowContext, workflow


@workflow(name="invoice")
async def invoice(ctx: WorkflowContext, customer: str) -> str:
    number = ctx.random.uuid()
    issued_at = ctx.time.now()
    return f"invoice {number} for {customer}, issued at {issued_at.isoformat()}"
Testing: run workflows in memory

orcher.testing runs a workflow without an engine, with its tasks mocked by name. With pytest and pytest-asyncio:

import pytest

from orcher.testing import TestWorkflowEnvironment

from orders import confirm_order


@pytest.mark.asyncio
async def test_confirms_the_order() -> None:
    env = TestWorkflowEnvironment()
    env.mock_task("send-confirmation").returns("sent")

    receipt = await env.execute_workflow(
        confirm_order, {"order_id": "order-1", "email": "ada@example.com"}
    )

    assert receipt == "sent"
    env.assert_task_called_with(
        "send-confirmation", {"order_id": "order-1", "email": "ada@example.com"}
    )

Mocks can also raise, return a sequence or compute their result, and the environment controls the clock.


Contributing

Issues and pull requests are welcome. See CONTRIBUTING.md for how to build, test and propose a change.

License

Licensed under the Apache License, Version 2.0.

"Python" and the Python logos are trademarks or registered trademarks of the Python Software Foundation, shown here to indicate the language this SDK is for.

Metadata

Release files for orcher-sdk 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for orcher-sdk 0.4.0
File Size Uploaded
orcher_sdk-0.4.0.tar.gz 245.9 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for orcher-sdk 0.4.0
File
orcher_sdk-0.4.0-cp311-abi3-musllinux_1_2_x86_64.whl CPython 3.11 abi3 Linux musl 1.2+ x86-64 Details
orcher_sdk-0.4.0-cp311-abi3-musllinux_1_2_aarch64.whl CPython 3.11 abi3 Linux musl 1.2+ ARM64 Details
orcher_sdk-0.4.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.11 abi3 Linux glibc 2.17+ x86-64 Details
orcher_sdk-0.4.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.11 abi3 Linux glibc 2.17+ ARM64 Details
orcher_sdk-0.4.0-cp311-abi3-macosx_11_0_arm64.whl CPython 3.11 abi3 macOS 11.0+ ARM64 Details
orcher_sdk-0.4.0-cp311-abi3-macosx_10_12_x86_64.whl CPython 3.11 abi3 macOS 10.12+ x86-64 Details

Total release size: 32.0 MB

Release files / orcher_sdk-0.4.0.tar.gz

Download URL orcher_sdk-0.4.0.tar.gz
Size 245.9 kB
Tags Source
SHA-256 checksum
How to use checksums
f95edd55fefd5a465e7a1993c7318462a0708cabb9b127b9e09efc513dfb238d
BLAKE2b-256 checksum
How to use checksums
088d4eb482a668ea9267a434ccd188d20fdf90523709a923cce9e30fcad3cf83
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / orcher_sdk-0.4.0-cp311-abi3-musllinux_1_2_x86_64.whl

Download URL orcher_sdk-0.4.0-cp311-abi3-musllinux_1_2_x86_64.whl
Size 5.7 MB
Tags CPython 3.11 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
7e0649b42eb84b1313e58c67c8cfeb5e899cd2dee8048c980bb3093b8df7739d
BLAKE2b-256 checksum
How to use checksums
8586be9b29dbbbd6c1a0de5e4132c1a3fcfb9d29e496f2117bfe9592e0418635
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / orcher_sdk-0.4.0-cp311-abi3-musllinux_1_2_aarch64.whl

Download URL orcher_sdk-0.4.0-cp311-abi3-musllinux_1_2_aarch64.whl
Size 5.7 MB
Tags CPython 3.11 Linux musl 1.2+ ARM64 abi3
SHA-256 checksum
How to use checksums
29d38a4c1922b983fa5c161f4498d5d356acda5d2e7d0557a004a63610d7808e
BLAKE2b-256 checksum
How to use checksums
d0974ea6ec542779d50b1a013a2079edcd38a4efd6a886f8ca6b58a3fbfd47a5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / orcher_sdk-0.4.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL orcher_sdk-0.4.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 5.2 MB
Tags CPython 3.11 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
cc69f7a62d332f5695fef638b481cb177ac0fa6c4292df66e3ccd6181f69ea2a
BLAKE2b-256 checksum
How to use checksums
eee091d6b9021906a8b1b64cf3ad7bb250acfef0df31560b7a79f68e5a71233c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / orcher_sdk-0.4.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL orcher_sdk-0.4.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 5.5 MB
Tags CPython 3.11 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
ba1d21cd22dd25dd8b18a7424858857c420d64c0bf856fb7b30700fc74544931
BLAKE2b-256 checksum
How to use checksums
9f01ff2dab02dc5097ceb1bf293a5ee1bd8ab2944ce5238f8f64f1f24ba7ccf7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / orcher_sdk-0.4.0-cp311-abi3-macosx_11_0_arm64.whl

Download URL orcher_sdk-0.4.0-cp311-abi3-macosx_11_0_arm64.whl
Size 4.8 MB
Tags CPython 3.11 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
deb1e01e98e75ff3b647d597c6a47b2cdce7dc655d4787f72a63ae96460ec385
BLAKE2b-256 checksum
How to use checksums
2301de5505389864afb1e9f61545d373572aa9577fa3fb7c0abd34662f5ea8c8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / orcher_sdk-0.4.0-cp311-abi3-macosx_10_12_x86_64.whl

Download URL orcher_sdk-0.4.0-cp311-abi3-macosx_10_12_x86_64.whl
Size 4.9 MB
Tags CPython 3.11 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
42eed35c82daa22c03b221f47a957cac144212313a5bf1b128916eaf196bfd50
BLAKE2b-256 checksum
How to use checksums
14c3ec7c3adfd867b1bee352baf58bf00641545c9c8c128ac29acfd42734ea87
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release history Release notifications | RSS feed

0.4.1

7 release files

This release

0.4.0 This release

7 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page