Skip to content

Commit c60e9bb

Browse files
greenie-msftNicholas Greenfieldberndverst
authored
Cleanup readme (#48)
* First pass at cleaning up the readme * Fix README instructions to add pre-reqs * continue to clean up instructions * Restore development text * Address PR feedback and change all examples to use DTS * Fix CI * Fix linting issues * Update docs/development.md --------- Co-authored-by: Nicholas Greenfield <nickgreenfield1@Nicks-Mac-mini.local> Co-authored-by: Bernd Verst <github@bernd.dev>
1 parent e5a297c commit c60e9bb

19 files changed

+754
-605
lines changed

.github/workflows/durabletask-azuremanaged.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ jobs:
6767
pip install -r requirements.txt
6868
6969
- name: Install durabletask-azuremanaged dependencies
70-
working-directory: examples/dts
70+
working-directory: examples
7171
run: |
7272
python -m pip install --upgrade pip
7373
pip install -r requirements.txt

CONTRIBUTING.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Contributing
2+
3+
This project welcomes contributions and suggestions. Most contributions require you to agree to a
4+
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
5+
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
6+
7+
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
8+
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
9+
provided by the bot. You will only need to do this once across all repos using our CLA.
10+
11+
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
12+
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
13+
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

README.md

Lines changed: 8 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -4,208 +4,18 @@
44
[![Build Validation](https://github.com/microsoft/durabletask-python/actions/workflows/pr-validation.yml/badge.svg)](https://github.com/microsoft/durabletask-python/actions/workflows/pr-validation.yml)
55
[![PyPI version](https://badge.fury.io/py/durabletask.svg)](https://badge.fury.io/py/durabletask)
66

7-
This repo contains a Python SDK for use with the [Azure Durable Task Scheduler](https://techcommunity.microsoft.com/blog/appsonazureblog/announcing-limited-early-access-of-the-durable-task-scheduler-for-azure-durable-/4286526) and the [Durable Task Framework for Go](https://github.com/microsoft/durabletask-go). With this SDK, you can define, schedule, and manage durable orchestrations using ordinary Python code.
7+
This repo contains a Python SDK for use with the [Azure Durable Task Scheduler](https://github.com/Azure/Durable-Task-Scheduler). With this SDK, you can define, schedule, and manage durable orchestrations using ordinary Python code.
88

9-
⚠️ **This SDK is currently under active development and is not yet ready for production use.** ⚠️
9+
> Note that this SDK is **not** currently compatible with [Azure Durable Functions](https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-overview). If you are looking for a Python SDK for Azure Durable Functions, please see [this repo](https://github.com/Azure/azure-functions-durable-python).
1010
11-
> Note that this SDK is **not** currently compatible with [Azure Durable Functions](https://docs.microsoft.com/azure/azure-functions/durable/durable-functions-overview). If you are looking for a Python SDK for Azure Durable Functions, please see [this repo](https://github.com/Azure/azure-functions-durable-python).
12-
13-
## Supported patterns
14-
15-
The following orchestration patterns are currently supported.
16-
17-
### Function chaining
18-
19-
An orchestration can chain a sequence of function calls using the following syntax:
20-
21-
```python
22-
# simple activity function that returns a greeting
23-
def hello(ctx: task.ActivityContext, name: str) -> str:
24-
return f'Hello {name}!'
25-
26-
# orchestrator function that sequences the activity calls
27-
def sequence(ctx: task.OrchestrationContext, _):
28-
result1 = yield ctx.call_activity(hello, input='Tokyo')
29-
result2 = yield ctx.call_activity(hello, input='Seattle')
30-
result3 = yield ctx.call_activity(hello, input='London')
31-
32-
return [result1, result2, result3]
33-
```
34-
35-
You can find the full sample [here](./examples/activity_sequence.py).
36-
37-
### Fan-out/fan-in
38-
39-
An orchestration can fan-out a dynamic number of function calls in parallel and then fan-in the results using the following syntax:
40-
41-
```python
42-
# activity function for getting the list of work items
43-
def get_work_items(ctx: task.ActivityContext, _) -> List[str]:
44-
# ...
45-
46-
# activity function for processing a single work item
47-
def process_work_item(ctx: task.ActivityContext, item: str) -> int:
48-
# ...
49-
50-
# orchestrator function that fans-out the work items and then fans-in the results
51-
def orchestrator(ctx: task.OrchestrationContext, _):
52-
# the number of work-items is unknown in advance
53-
work_items = yield ctx.call_activity(get_work_items)
54-
55-
# fan-out: schedule the work items in parallel and wait for all of them to complete
56-
tasks = [ctx.call_activity(process_work_item, input=item) for item in work_items]
57-
results = yield task.when_all(tasks)
58-
59-
# fan-in: summarize and return the results
60-
return {'work_items': work_items, 'results': results, 'total': sum(results)}
61-
```
62-
63-
You can find the full sample [here](./examples/fanout_fanin.py).
64-
65-
### Human interaction and durable timers
66-
67-
An orchestration can wait for a user-defined event, such as a human approval event, before proceding to the next step. In addition, the orchestration can create a timer with an arbitrary duration that triggers some alternate action if the external event hasn't been received:
68-
69-
```python
70-
def purchase_order_workflow(ctx: task.OrchestrationContext, order: Order):
71-
"""Orchestrator function that represents a purchase order workflow"""
72-
# Orders under $1000 are auto-approved
73-
if order.Cost < 1000:
74-
return "Auto-approved"
75-
76-
# Orders of $1000 or more require manager approval
77-
yield ctx.call_activity(send_approval_request, input=order)
78-
79-
# Approvals must be received within 24 hours or they will be canceled.
80-
approval_event = ctx.wait_for_external_event("approval_received")
81-
timeout_event = ctx.create_timer(timedelta(hours=24))
82-
winner = yield task.when_any([approval_event, timeout_event])
83-
if winner == timeout_event:
84-
return "Canceled"
85-
86-
# The order was approved
87-
yield ctx.call_activity(place_order, input=order)
88-
approval_details = approval_event.get_result()
89-
return f"Approved by '{approval_details.approver}'"
90-
```
91-
92-
As an aside, you'll also notice that the example orchestration above works with custom business objects. Support for custom business objects includes support for custom classes, custom data classes, and named tuples. Serialization and deserialization of these objects is handled automatically by the SDK.
93-
94-
You can find the full sample [here](./examples/human_interaction.py).
95-
96-
## Feature overview
97-
98-
The following features are currently supported:
99-
100-
### Orchestrations
101-
102-
Orchestrations are implemented using ordinary Python functions that take an `OrchestrationContext` as their first parameter. The `OrchestrationContext` provides APIs for starting child orchestrations, scheduling activities, and waiting for external events, among other things. Orchestrations are fault-tolerant and durable, meaning that they can automatically recover from failures and rebuild their local execution state. Orchestrator functions must be deterministic, meaning that they must always produce the same output given the same input.
103-
104-
### Activities
105-
106-
Activities are implemented using ordinary Python functions that take an `ActivityContext` as their first parameter. Activity functions are scheduled by orchestrations and have at-least-once execution guarantees, meaning that they will be executed at least once but may be executed multiple times in the event of a transient failure. Activity functions are where the real "work" of any orchestration is done.
107-
108-
### Durable timers
109-
110-
Orchestrations can schedule durable timers using the `create_timer` API. These timers are durable, meaning that they will survive orchestrator restarts and will fire even if the orchestrator is not actively in memory. Durable timers can be of any duration, from milliseconds to months.
111-
112-
### Sub-orchestrations
113-
114-
Orchestrations can start child orchestrations using the `call_sub_orchestrator` API. Child orchestrations are useful for encapsulating complex logic and for breaking up large orchestrations into smaller, more manageable pieces.
115-
116-
### External events
117-
118-
Orchestrations can wait for external events using the `wait_for_external_event` API. External events are useful for implementing human interaction patterns, such as waiting for a user to approve an order before continuing.
119-
120-
### Continue-as-new (TODO)
121-
122-
Orchestrations can be continued as new using the `continue_as_new` API. This API allows an orchestration to restart itself from scratch, optionally with a new input.
123-
124-
### Suspend, resume, and terminate
125-
126-
Orchestrations can be suspended using the `suspend_orchestration` client API and will remain suspended until resumed using the `resume_orchestration` client API. A suspended orchestration will stop processing new events, but will continue to buffer any that happen to arrive until resumed, ensuring that no data is lost. An orchestration can also be terminated using the `terminate_orchestration` client API. Terminated orchestrations will stop processing new events and will discard any buffered events.
127-
128-
### Retry policies (TODO)
129-
130-
Orchestrations can specify retry policies for activities and sub-orchestrations. These policies control how many times and how frequently an activity or sub-orchestration will be retried in the event of a transient error.
131-
132-
## Getting Started
133-
134-
### Prerequisites
135-
136-
- Python 3.9
137-
- A Durable Task-compatible sidecar, like [Dapr Workflow](https://docs.dapr.io/developing-applications/building-blocks/workflow/workflow-overview/)
138-
139-
### Installing the Durable Task Python client SDK
140-
141-
Installation is currently only supported from source. Ensure pip, setuptools, and wheel are up-to-date.
142-
143-
```sh
144-
python3 -m pip install --upgrade pip setuptools wheel
145-
```
146-
147-
To install this package from source, clone this repository and run the following command from the project root:
148-
149-
```sh
150-
python3 -m pip install .
151-
```
152-
153-
### Run the samples
154-
155-
See the [examples](./examples) directory for a list of sample orchestrations and instructions on how to run them.
156-
157-
## Development
158-
159-
The following is more information about how to develop this project. Note that development commands require that `make` is installed on your local machine. If you're using Windows, you can install `make` using [Chocolatey](https://chocolatey.org/) or use WSL.
160-
161-
### Generating protobufs
162-
163-
```sh
164-
pip3 install -r dev-requirements.txt
165-
make gen-proto
166-
```
167-
168-
This will download the `orchestrator_service.proto` from the `microsoft/durabletask-protobuf` repo and compile it using `grpcio-tools`. The version of the source proto file that was downloaded can be found in the file `durabletask/internal/PROTO_SOURCE_COMMIT_HASH`.
169-
170-
### Running unit tests
171-
172-
Unit tests can be run using the following command from the project root. Unit tests _don't_ require a sidecar process to be running.
173-
174-
```sh
175-
make test-unit
176-
```
177-
178-
### Running E2E tests
179-
180-
The E2E (end-to-end) tests require a sidecar process to be running. You can use the Dapr sidecar for this or run a Durable Task test sidecar using the following command:
181-
182-
```sh
183-
go install github.com/microsoft/durabletask-go@main
184-
durabletask-go --port 4001
185-
```
186-
187-
To run the E2E tests, run the following command from the project root:
188-
189-
```sh
190-
make test-e2e
191-
```
192-
193-
## Contributing
194-
195-
This project welcomes contributions and suggestions. Most contributions require you to agree to a
196-
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
197-
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
198-
199-
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
200-
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
201-
provided by the bot. You will only need to do this once across all repos using our CLA.
202-
203-
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
204-
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
205-
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
11+
# References
12+
- [Supported Patterns](./docs/supported-patterns.md)
13+
- [Available Features](./docs/features.md)
14+
- [Getting Started](./docs/getting-started.md)
15+
- [Development Guide](./docs/development.md)
16+
- [Contributing Guide](./CONTRIBUTING.md)
20617

20718
## Trademarks
208-
20919
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
21020
trademarks or logos is subject to and must follow
21121
[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).

docs/development.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Development
2+
3+
The following is more information about how to develop this project. Note that development commands require that `make` is installed on your local machine. If you're using Windows, you can install `make` using [Chocolatey](https://chocolatey.org/) or use WSL.
4+
5+
### Generating protobufs
6+
7+
```sh
8+
pip3 install -r dev-requirements.txt
9+
make gen-proto
10+
```
11+
12+
This will download the `orchestrator_service.proto` from the `microsoft/durabletask-protobuf` repo and compile it using `grpcio-tools`. The version of the source proto file that was downloaded can be found in the file `durabletask/internal/PROTO_SOURCE_COMMIT_HASH`.
13+
14+
### Running unit tests
15+
16+
Unit tests can be run using the following command from the project root. Unit tests _don't_ require a sidecar process to be running.
17+
18+
```sh
19+
make test-unit
20+
```
21+
22+
### Running E2E tests
23+
24+
The E2E (end-to-end) tests require a sidecar process to be running. You can use the Durable Task test sidecar using the following `docker` command:
25+
26+
```sh
27+
go install github.com/microsoft/durabletask-go@main
28+
durabletask-go --port 4001
29+
```
30+
31+
To run the E2E tests, run the following command from the project root:
32+
33+
```sh
34+
make test-e2e
35+
```

docs/features.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Feature overview
2+
3+
The following features are currently supported:
4+
5+
### Orchestrations
6+
7+
Orchestrations are implemented using ordinary Python functions that take an `OrchestrationContext` as their first parameter. The `OrchestrationContext` provides APIs for starting child orchestrations, scheduling activities, and waiting for external events, among other things. Orchestrations are fault-tolerant and durable, meaning that they can automatically recover from failures and rebuild their local execution state. Orchestrator functions must be deterministic, meaning that they must always produce the same output given the same input.
8+
9+
### Activities
10+
11+
Activities are implemented using ordinary Python functions that take an `ActivityContext` as their first parameter. Activity functions are scheduled by orchestrations and have at-least-once execution guarantees, meaning that they will be executed at least once but may be executed multiple times in the event of a transient failure. Activity functions are where the real "work" of any orchestration is done.
12+
13+
### Durable timers
14+
15+
Orchestrations can schedule durable timers using the `create_timer` API. These timers are durable, meaning that they will survive orchestrator restarts and will fire even if the orchestrator is not actively in memory. Durable timers can be of any duration, from milliseconds to months.
16+
17+
### Sub-orchestrations
18+
19+
Orchestrations can start child orchestrations using the `call_sub_orchestrator` API. Child orchestrations are useful for encapsulating complex logic and for breaking up large orchestrations into smaller, more manageable pieces.
20+
21+
### External events
22+
23+
Orchestrations can wait for external events using the `wait_for_external_event` API. External events are useful for implementing human interaction patterns, such as waiting for a user to approve an order before continuing.
24+
25+
### Continue-as-new
26+
27+
Orchestrations can be continued as new using the `continue_as_new` API. This API allows an orchestration to restart itself from scratch, optionally with a new input.
28+
29+
### Suspend, resume, and terminate
30+
31+
Orchestrations can be suspended using the `suspend_orchestration` client API and will remain suspended until resumed using the `resume_orchestration` client API. A suspended orchestration will stop processing new events, but will continue to buffer any that happen to arrive until resumed, ensuring that no data is lost. An orchestration can also be terminated using the `terminate_orchestration` client API. Terminated orchestrations will stop processing new events and will discard any buffered events.
32+
33+
### Retry policies
34+
35+
Orchestrations can specify retry policies for activities and sub-orchestrations. These policies control how many times and how frequently an activity or sub-orchestration will be retried in the event of a transient error.

docs/getting-started.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Getting Started
2+
3+
### Run the Order Processing Example
4+
- Check out the [Durable Task Scheduler example](../examples/dts/sub-orchestrations-with-fan-out-fan-in/README.md)
5+
for detailed instructions on running the order processing example.
6+
7+
### Explore Other Samples
8+
- Visit the [examples](../examples/dts/) directory to find a variety of sample orchestrations and learn how to run them.
9+

0 commit comments

Comments
 (0)