Skip to content

Commit b15778e

Browse files
Give the Python SDK a task-oriented developer landing page
1 parent cb1c5ff commit b15778e

4 files changed

Lines changed: 405 additions & 74 deletions

File tree

docs/index.md

Lines changed: 125 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
---
22
title: Durable Workflow Python SDK
3-
description: Build durable Python workflows with an async-first SDK for self-hosted Server or the limited-access Cloud runtime.
3+
description: Install the first-party Python SDK and run a durable workflow on self-hosted Server or a managed Cloud runtime.
44
hide:
55
- toc
66
---
77

8-
<div class="dw-landing" data-docs-surface="python-sdk-landing" markdown="1">
8+
<div class="dw-landing" data-docs-surface="python-sdk-landing" data-sdk-release="{{ durable_workflow_sdk_version }}" markdown="1">
99

10-
<section class="dw-hero" aria-labelledby="durable-workflows-written-in-python" markdown="1">
10+
<section class="dw-hero" aria-labelledby="durable-workflows-in-python" markdown="1">
1111

1212
<div class="dw-hero__copy" markdown="1">
1313

14-
<p class="dw-eyebrow">Python SDK · release candidate</p>
14+
<p class="dw-eyebrow">First-party Python SDK · 2.0 prerelease</p>
1515

16-
# Durable workflows, written in Python.
16+
# Durable workflows in Python.
1717

18-
Build async clients and workers for long-running, retryable work. Start with a
19-
local self-hosted Server—no Cloud account is required.
18+
Define workflows and activities, run an async worker, and start durable work
19+
from Python. Begin with self-hosted Server or connect an existing managed Cloud
20+
namespace.
2021

2122
<div class="dw-hero__actions">
22-
<a class="dw-button dw-button--primary" data-docs-destination="local-self-hosted" data-access="no-account-required" href="#first-workflow">Run your first workflow <span aria-hidden="true">→</span></a>
23-
<a class="dw-button dw-button--secondary" data-docs-destination="sdk-guide" href="https://durable-workflow.com/docs/2.0/polyglot/python/">Read the SDK guide</a>
24-
<a class="dw-text-link" data-docs-destination="api-reference" href="reference/client/">Browse API reference</a>
23+
<a class="dw-button dw-button--primary" data-docs-destination="local-self-hosted" data-access="no-account-required" href="#first-workflow">Run with Server <span aria-hidden="true">→</span></a>
24+
<a class="dw-button dw-button--secondary" data-docs-destination="managed-cloud" data-access="limited" href="#managed-cloud">Connect to Cloud</a>
25+
<a class="dw-text-link" data-docs-destination="api-reference" href="reference/client/">API reference</a>
2526
</div>
2627

2728
<p class="dw-hero__facts"><span>Python 3.10+</span><span>Async-first</span><span>Fully typed</span></p>
@@ -36,8 +37,8 @@ local self-hosted Server—no Cloud account is required.
3637
pip install '{{ durable_workflow_install_requirement }}'
3738
```
3839

39-
The compatible-release constraint follows the supported 2.0 prerelease
40-
channel without pinning this page to one release-candidate number.
40+
The requirement is rendered from the SDK's current package and compatibility
41+
authority instead of being copied into this page.
4142

4243
<p class="dw-install-card__links"><a data-docs-destination="pypi" href="https://pypi.org/project/durable-workflow/">View on PyPI</a><a data-docs-destination="github" href="https://github.com/durable-workflow/sdk-python">Source on GitHub</a></p>
4344

@@ -61,70 +62,112 @@ dispatches them to your workflow and activity code.
6162

6263
</section>
6364

64-
<section class="dw-section dw-first-run" id="first-workflow" data-docs-journey="local-self-hosted" aria-labelledby="run-your-first-local-workflow" markdown="1">
65+
<section class="dw-section dw-runtime" id="runtime-choices" aria-labelledby="choose-who-runs-the-runtime" markdown="1">
66+
67+
## Choose who runs the runtime
68+
69+
The workflow types, activity types, and task queue stay the same. Only the
70+
endpoint, credentials, and operating boundary change.
71+
72+
<div class="dw-runtime-grid">
73+
<article class="dw-runtime-card dw-runtime-card--primary" data-runtime="self-hosted" data-access="no-account-required">
74+
<span class="dw-tag">Available without an account</span>
75+
<h3>Self-hosted Server</h3>
76+
<p>Run the published Server image locally, then execute the complete Python journey below.</p>
77+
<a class="dw-button dw-button--primary" data-docs-destination="self-hosted-quickstart" href="#first-workflow">Start locally <span aria-hidden="true">→</span></a>
78+
</article>
79+
<article class="dw-runtime-card dw-runtime-card--secondary dw-cloud-promotion" data-runtime="cloud" data-access="limited" data-promotion-source="sdk-python-reference">
80+
<span class="dw-cloud-promotion__eyebrow dw-tag">Managed runtime · limited access</span>
81+
<h3>Durable Workflow Cloud</h3>
82+
<p>Connect the same program to a provisioned namespace with separate client and worker credentials.</p>
83+
<p class="dw-runtime-card__actions">
84+
<a class="dw-button dw-button--secondary" data-docs-destination="cloud-quickstart" href="#managed-cloud">Connect a namespace</a>
85+
<a class="dw-cloud-promotion__action" data-docs-destination="cloud-access" data-promotion-action="early-access" href="https://cloud.durable-workflow.com/early-access#source=sdk-python-reference">Request early access →</a>
86+
</p>
87+
</article>
88+
</div>
89+
90+
</section>
91+
92+
<section class="dw-section dw-first-run" id="first-workflow" data-docs-journey="local-self-hosted" data-workflow-type="python.greeter" data-activity-type="python.greet" data-task-queue="python-workers" aria-labelledby="run-your-first-local-workflow" markdown="1">
6593

6694
## Run your first local workflow
6795

68-
This source-free development path runs the compatibility-qualified Server image
69-
on your machine, then connects one Python client and worker to it.
96+
This source-free path starts the compatibility-qualified Server image, then
97+
runs one Python file containing an activity, workflow, worker, and client.
7098

71-
### 1. Start the compatible Server
99+
### 1. Start Server
72100

73-
Docker keeps this first run local. The image tag below is rendered from the
74-
SDK's compatibility authority, alongside the package version shown on this
75-
page.
101+
Docker keeps this first run local. The image below is rendered from the same
102+
compatibility authority as the install command.
76103

77104
```bash
78105
export DW_SERVER_IMAGE='durableworkflow/server:{{ durable_workflow_server_version }}'
79-
export DW_AUTH_TOKEN=dev-token
106+
export DURABLE_WORKFLOW_RUNTIME_URL='http://127.0.0.1:8080'
107+
export DURABLE_WORKFLOW_RUNTIME_NAMESPACE='default'
108+
export DURABLE_WORKFLOW_TOKEN='local-python-example-token'
80109
docker volume create durable-workflow-python
81110
docker run --rm -v durable-workflow-python:/app/database \
82-
-e DW_AUTH_DRIVER=token -e DW_AUTH_TOKEN="$DW_AUTH_TOKEN" \
111+
-e DW_AUTH_DRIVER=token -e DW_AUTH_TOKEN="$DURABLE_WORKFLOW_TOKEN" \
83112
"$DW_SERVER_IMAGE" server-bootstrap
84113
docker rm -f durable-workflow-python-server >/dev/null 2>&1 || true
85114
docker run -d --name durable-workflow-python-server -p 8080:8080 \
86115
-v durable-workflow-python:/app/database \
87-
-e DW_AUTH_DRIVER=token -e DW_AUTH_TOKEN="$DW_AUTH_TOKEN" \
116+
-e DW_AUTH_DRIVER=token -e DW_AUTH_TOKEN="$DURABLE_WORKFLOW_TOKEN" \
88117
"$DW_SERVER_IMAGE"
89-
until curl -sf http://localhost:8080/api/ready >/dev/null; do sleep 1; done
118+
until curl -sf http://127.0.0.1:8080/api/ready >/dev/null; do sleep 1; done
90119
```
91120

92121
### 2. Save `greeter.py`
93122

123+
The named constants make the authoring contract visible: the decorator and
124+
start call share a workflow type, the workflow and decorator share an activity
125+
type, and the client and worker share one task queue. Values cross those
126+
boundaries with the supported Avro authoring codec.
127+
94128
```python
95129
import asyncio
130+
import logging
131+
import os
96132
from uuid import uuid4
97133

98134
from durable_workflow import Client, Worker, activity, workflow
99135

136+
WORKFLOW_TYPE = "python.greeter"
137+
ACTIVITY_TYPE = "python.greet"
138+
TASK_QUEUE = "python-workers"
139+
100140

101-
@activity.defn(name="greet")
141+
@activity.defn(name=ACTIVITY_TYPE)
102142
def greet(name: str) -> str:
103143
return f"Hello, {name}!"
104144

105145

106-
@workflow.defn(name="greeter")
146+
@workflow.defn(name=WORKFLOW_TYPE)
107147
class GreeterWorkflow:
108148
def run(self, ctx, name):
109-
return (yield ctx.schedule_activity("greet", [name]))
149+
return (yield ctx.schedule_activity(ACTIVITY_TYPE, [name]))
110150

111151

112152
async def main() -> None:
153+
logging.basicConfig(level=logging.INFO, format="%(message)s")
113154
async with Client(
114-
"http://localhost:8080",
115-
token="dev-token",
116-
namespace="default",
155+
os.environ["DURABLE_WORKFLOW_RUNTIME_URL"],
156+
token=os.getenv("DURABLE_WORKFLOW_TOKEN"),
157+
control_token=os.getenv("DURABLE_WORKFLOW_CLIENT_TOKEN"),
158+
worker_token=os.getenv("DURABLE_WORKFLOW_WORKER_TOKEN"),
159+
namespace=os.environ["DURABLE_WORKFLOW_RUNTIME_NAMESPACE"],
117160
) as client:
118161
worker = Worker(
119162
client,
120-
task_queue="python-workers",
163+
task_queue=TASK_QUEUE,
121164
workflows=[GreeterWorkflow],
122165
activities=[greet],
123166
)
124167
handle = await client.start_workflow(
125-
workflow_type="greeter",
168+
workflow_type=WORKFLOW_TYPE,
126169
workflow_id=f"greeting-{uuid4().hex}",
127-
task_queue="python-workers",
170+
task_queue=TASK_QUEUE,
128171
input=["world"],
129172
)
130173
await worker.run_until(workflow_id=handle.workflow_id, timeout=30.0)
@@ -140,46 +183,66 @@ asyncio.run(main())
140183
python greeter.py
141184
```
142185

143-
The client starts a durable workflow instance. The worker executes the workflow
144-
and its activity, and the final line prints `Hello, world!`. Continue with the
145-
[complete Python SDK guide](https://durable-workflow.com/docs/2.0/polyglot/python/)
146-
for messages, retries, tests, credentials, and production worker operation.
186+
<div class="dw-checkpoint" data-worker-ready-output="registered" markdown="1">
187+
188+
The SDK reports registration before it handles the workflow, followed by the
189+
completed result:
190+
191+
```text
192+
worker py-worker-… registered on python-workers
193+
Hello, world!
194+
```
195+
196+
</div>
147197

148198
</section>
149199

150-
<section class="dw-section dw-runtime" id="runtime-choices" aria-labelledby="choose-who-runs-the-runtime" markdown="1">
200+
<section class="dw-section dw-cloud-path" id="managed-cloud" data-docs-journey="managed-cloud" data-runtime-url-contract="provisioned-namespace-root" aria-labelledby="connect-a-managed-cloud-namespace" markdown="1">
151201

152-
## Choose who runs the runtime
202+
## Connect a managed Cloud namespace
153203

154-
Your Python workflow code and task queue model stay the same. The endpoint,
155-
credentials, and operating boundary change.
204+
Cloud provisioning returns a namespace-scoped runtime URL and namespace value.
205+
Pass that complete runtime URL unchanged; do not invent or append an `/api`
206+
suffix because the SDK adds its own routes.
156207

157-
<div class="dw-runtime-grid">
158-
<article class="dw-runtime-card dw-runtime-card--primary" data-runtime="self-hosted" data-access="no-account-required">
159-
<span class="dw-tag">Available without an account</span>
160-
<h3>Self-hosted Server</h3>
161-
<p>Run the published Server image with your database, authentication policy, and operational controls.</p>
162-
<a class="dw-button dw-button--primary" data-docs-destination="self-hosting-guide" href="https://durable-workflow.com/docs/2.0/polyglot/server/">Open the Server guide <span aria-hidden="true">→</span></a>
163-
</article>
164-
<article class="dw-runtime-card dw-runtime-card--secondary dw-cloud-promotion" data-runtime="cloud" data-access="limited" data-promotion-source="sdk-python-reference">
165-
<span class="dw-cloud-promotion__eyebrow dw-tag">Managed runtime · limited access</span>
166-
<h3>Durable Workflow Cloud</h3>
167-
<p>Use a provisioned namespace URL and separate client and worker credentials while Durable Workflow operates the runtime.</p>
168-
<a class="dw-cloud-promotion__action" data-promotion-action="early-access" href="https://cloud.durable-workflow.com/early-access#source=sdk-python-reference">Request early access →</a>
169-
</article>
170-
</div>
208+
### Use each credential for one job
209+
210+
<ul class="dw-credential-grid">
211+
<li data-credential-role="control-plane-api-key"><strong>Control-plane API key</strong><span>Creates and administers Cloud resources and runtime credentials. It is not passed to the Python SDK runtime client.</span></li>
212+
<li data-credential-role="runtime-client-token"><strong>Runtime client token</strong><span>Starts and controls workflows in one namespace. Pass it through <code>DURABLE_WORKFLOW_CLIENT_TOKEN</code>, which maps to <code>control_token=</code>.</span></li>
213+
<li data-credential-role="runtime-worker-token"><strong>Runtime worker token</strong><span>Registers, polls, heartbeats, and completes work in that namespace. Pass it through <code>DURABLE_WORKFLOW_WORKER_TOKEN</code>, which maps to <code>worker_token=</code>.</span></li>
214+
</ul>
215+
216+
Replace the placeholders with values returned for your namespace, then run the
217+
same `greeter.py`. Keep client and worker tokens in their respective processes
218+
when you split the example for production.
219+
220+
```bash
221+
export DURABLE_WORKFLOW_RUNTIME_URL='<provisioned-runtime-url>'
222+
export DURABLE_WORKFLOW_RUNTIME_NAMESPACE='<provisioned-runtime-namespace>'
223+
export DURABLE_WORKFLOW_CLIENT_TOKEN='<runtime-client-token>'
224+
export DURABLE_WORKFLOW_WORKER_TOKEN='<runtime-worker-token>'
225+
unset DURABLE_WORKFLOW_TOKEN
226+
python greeter.py
227+
```
228+
229+
<p class="dw-inline-actions"><a class="dw-button dw-button--secondary" data-docs-destination="cloud-guide" href="https://durable-workflow.com/docs/2.0/polyglot/cloud-control-plane/">Cloud runtime guide</a><a class="dw-text-link" data-docs-destination="python-playground" href="https://github.com/durable-workflow/sample-app#symmetric-sdk-playground">Run the Python playground →</a></p>
171230

172231
</section>
173232

174-
<section class="dw-section dw-depth" aria-labelledby="go-deeper-when-you-need-it" markdown="1">
233+
<section class="dw-section dw-depth" aria-labelledby="continue-building" markdown="1">
175234

176-
## Go deeper when you need it
235+
## Continue building
177236

178237
<div class="dw-link-grid">
179238
<a class="dw-link-card" data-docs-destination="sdk-guide" href="https://durable-workflow.com/docs/2.0/polyglot/python/"><strong>Python SDK guide</strong><span>Tutorials, architecture, testing, and operations.</span><span>Read the guide →</span></a>
180239
<a class="dw-link-card" data-docs-destination="api-reference" href="reference/client/"><strong>Generated API reference</strong><span>Signatures, return types, exceptions, and public modules.</span><span>Browse reference →</span></a>
181240
<a class="dw-link-card" data-docs-destination="pypi" href="https://pypi.org/project/durable-workflow/"><strong>PyPI package</strong><span>Release files, Python requirements, and package metadata.</span><span>Open PyPI →</span></a>
182-
<a class="dw-link-card" data-docs-destination="github" href="https://github.com/durable-workflow/sdk-python"><strong>GitHub repository</strong><span>Source, examples, changelog, and contribution guide.</span><span>View source →</span></a>
241+
<a class="dw-link-card" data-docs-destination="github" href="https://github.com/durable-workflow/sdk-python"><strong>SDK source</strong><span>Examples, changelog, source, and contribution guide.</span><span>View source →</span></a>
242+
<a class="dw-link-card" data-docs-destination="main-docs" href="https://durable-workflow.com/docs/2.0/introduction/"><strong>Durable Workflow 2.0 docs</strong><span>Concepts, runtime choices, operations, and platform guides.</span><span>Open the docs →</span></a>
243+
<a class="dw-link-card" data-docs-destination="capability-authority" href="https://durable-workflow.com/docs/2.0/capabilities/"><strong>Capability authority</strong><span>The supported SDK, runtime, protocol, and feature matrix.</span><span>Check capabilities →</span></a>
244+
<a class="dw-link-card" data-docs-destination="compatibility-authority" href="https://durable-workflow.com/docs/2.0/compatibility/"><strong>Version compatibility</strong><span>Compatibility contracts and machine-owned release boundaries.</span><span>Check compatibility →</span></a>
245+
<a class="dw-link-card" data-docs-destination="python-playground" href="https://github.com/durable-workflow/sample-app#symmetric-sdk-playground"><strong>Sample App Python playground</strong><span>A prepared, symmetric SDK journey with worker-ready checks.</span><span>Open the playground →</span></a>
183246
</div>
184247

185248
</section>
@@ -188,11 +251,11 @@ credentials, and operating boundary change.
188251

189252
## Versioning
190253

191-
This site is generated from the SDK source and keeps exact release identities
192-
in one machine-owned compatibility authority. It currently qualifies SDK
193-
`{{ durable_workflow_sdk_version }}` with
194-
`durableworkflow/server:{{ durable_workflow_server_version }}`. The SDK and
195-
Server advance independently; use the versions shown here together.
254+
<span hidden data-release-authority="package-metadata">SDK {{ durable_workflow_sdk_version }}; durableworkflow/server:{{ durable_workflow_server_version }}</span>
255+
256+
The install requirement and compatible Server image on this page are generated
257+
from the SDK package metadata. Lock the resolved package in your application
258+
when you need reproducible builds.
196259

197260
</section>
198261

0 commit comments

Comments
 (0)