Skip to content

Commit c9b7c8d

Browse files
authored
Merge pull request #228197 from davidmrdavid/dajusto/add-pystein-df-preview-docs
Add initial DF PyStein docs
2 parents 9e26218 + 6180ed7 commit c9b7c8d

File tree

2 files changed

+311
-29
lines changed

2 files changed

+311
-29
lines changed

articles/azure-functions/durable/durable-functions-overview.md

Lines changed: 181 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,16 @@ Durable Functions is designed to work with all Azure Functions programming langu
2323
| .NET / C# / F# | Functions 1.0+ | In-process <br/> Out-of-process| n/a |
2424
| JavaScript/TypeScript | Functions 2.0+ | Node 8+ | 2.x bundles |
2525
| Python | Functions 2.0+ | Python 3.7+ | 2.x bundles |
26+
| Python (V2 prog. model) | Functions 4.0+ | Python 3.7+ | 3.15+ bundles |
2627
| PowerShell | Functions 3.0+ | PowerShell 7+ | 2.x bundles |
2728
| Java | Functions 4.0+ | Java 8+ | 4.x bundles |
2829

29-
Like Azure Functions, there are templates to help you develop Durable Functions using [Visual Studio 2019](durable-functions-create-first-csharp.md), [Visual Studio Code](quickstart-js-vscode.md), and the [Azure portal](durable-functions-create-portal.md).
30+
> [!NOTE]
31+
> The new programming model for authoring Functions in Python (V2) is currently in preview. Compared to the current model, the new experience is designed to have a more idiomatic and intuitive. To learn more, see Azure Functions Python [developer guide](/azure/azure-functions/functions-reference-python.md?pivots=python-mode-decorators).
32+
>
33+
> In the following code snippets, Python (PM2) denotes programming model V2, the new experience.
34+
35+
Like Azure Functions, there are templates to help you develop Durable Functions using [Visual Studio](durable-functions-create-first-csharp.md), [Visual Studio Code](quickstart-js-vscode.md), and the [Azure portal](durable-functions-create-portal.md).
3036

3137
## Application patterns
3238

@@ -141,6 +147,29 @@ You can use the `context` object to invoke other functions by name, pass paramet
141147
> [!NOTE]
142148
> The `context` object in Python represents the orchestration context. Access the main Azure Functions context using the `function_context` property on the orchestration context.
143149
150+
# [Python (PM2)](#tab/python-v2)
151+
152+
```python
153+
import azure.functions as func
154+
import azure.durable_functions as df
155+
156+
myApp = df.DFApp(http_auth_level=func.AuthLevel.ANONYMOUS)
157+
158+
@myApp.orchestration_trigger(context_name="context")
159+
def orchestrator_function(context: df.DurableOrchestrationContext):
160+
x = yield context.call_activity("F1", None)
161+
y = yield context.call_activity("F2", x)
162+
z = yield context.call_activity("F3", y)
163+
result = yield context.call_activity("F4", z)
164+
return result
165+
166+
```
167+
168+
You can use the `context` object to invoke other functions by name, pass parameters, and return function output. Each time the code calls `yield`, the Durable Functions framework checkpoints the progress of the current function instance. If the process or virtual machine recycles midway through the execution, the function instance resumes from the preceding `yield` call. For more information, see the next section, Pattern #2: Fan out/fan in.
169+
170+
> [!NOTE]
171+
> The `context` object in Python represents the orchestration context. Access the main Azure Functions context using the `function_context` property on the orchestration context.
172+
144173
# [PowerShell](#tab/powershell)
145174

146175
```PowerShell
@@ -292,6 +321,32 @@ The fan-out work is distributed to multiple instances of the `F2` function. The
292321

293322
The automatic checkpointing that happens at the `yield` call on `context.task_all` ensures that a potential midway crash or reboot doesn't require restarting an already completed task.
294323

324+
# [Python (PM2)](#tab/python-v2)
325+
326+
```python
327+
import azure.functions as func
328+
import azure.durable_functions as df
329+
330+
myApp = df.DFApp(http_auth_level=func.AuthLevel.ANONYMOUS)
331+
332+
@myApp.orchestration_trigger(context_name="context")
333+
def orchestrator_function(context: df.DurableOrchestrationContext):
334+
# Get a list of N work items to process in parallel.
335+
work_batch = yield context.call_activity("F1", None)
336+
337+
parallel_tasks = [ context.call_activity("F2", b) for b in work_batch ]
338+
339+
outputs = yield context.task_all(parallel_tasks)
340+
341+
# Aggregate all N outputs and send the result to F3.
342+
total = sum(outputs)
343+
yield context.call_activity("F3", total)
344+
```
345+
346+
The fan-out work is distributed to multiple instances of the `F2` function. The work is tracked by using a dynamic list of tasks. `context.task_all` API is called to wait for all the called functions to finish. Then, the `F2` function outputs are aggregated from the dynamic task list and passed to the `F3` function.
347+
348+
The automatic checkpointing that happens at the `yield` call on `context.task_all` ensures that a potential midway crash or reboot doesn't require restarting an already completed task.
349+
295350
# [PowerShell](#tab/powershell)
296351

297352
```PowerShell
@@ -514,6 +569,38 @@ def orchestrator_function(context: df.DurableOrchestrationContext):
514569
main = df.Orchestrator.create(orchestrator_function)
515570
```
516571

572+
# [Python (PM2)](#tab/python-v2)
573+
574+
```python
575+
import json
576+
from datetime import timedelta
577+
578+
import azure.functions as func
579+
import azure.durable_functions as df
580+
581+
myApp = df.DFApp(http_auth_level=func.AuthLevel.ANONYMOUS)
582+
583+
@myApp.orchestration_trigger(context_name="context")
584+
def orchestrator_function(context: df.DurableOrchestrationContext):
585+
job = json.loads(context.get_input())
586+
job_id = job["jobId"]
587+
polling_interval = job["pollingInterval"]
588+
expiry_time = job["expiryTime"]
589+
590+
while context.current_utc_datetime < expiry_time:
591+
job_status = yield context.call_activity("GetJobStatus", job_id)
592+
if job_status == "Completed":
593+
# Perform an action when a condition is met.
594+
yield context.call_activity("SendAlert", job_id)
595+
break
596+
597+
# Orchestration sleeps until this time.
598+
next_check = context.current_utc_datetime + timedelta(seconds=polling_interval)
599+
yield context.create_timer(next_check)
600+
601+
# Perform more work here, or let the orchestration end.
602+
```
603+
517604
# [PowerShell](#tab/powershell)
518605

519606
```powershell
@@ -699,6 +786,36 @@ main = df.Orchestrator.create(orchestrator_function)
699786

700787
To create the durable timer, call `context.create_timer`. The notification is received by `context.wait_for_external_event`. Then, `context.task_any` is called to decide whether to escalate (timeout happens first) or process the approval (the approval is received before timeout).
701788

789+
# [Python (PM2)](#tab/python-v2)
790+
791+
```python
792+
import json
793+
from datetime import timedelta
794+
795+
import azure.functions as func
796+
import azure.durable_functions as df
797+
798+
myApp = df.DFApp(http_auth_level=func.AuthLevel.ANONYMOUS)
799+
800+
@myApp.orchestration_trigger(context_name="context")
801+
def orchestrator_function(context: df.DurableOrchestrationContext):
802+
yield context.call_activity("RequestApproval", None)
803+
804+
due_time = context.current_utc_datetime + timedelta(hours=72)
805+
durable_timeout_task = context.create_timer(due_time)
806+
approval_event_task = context.wait_for_external_event("ApprovalEvent")
807+
808+
winning_task = yield context.task_any([approval_event_task, durable_timeout_task])
809+
810+
if approval_event_task == winning_task:
811+
durable_timeout_task.cancel()
812+
yield context.call_activity("ProcessApproval", approval_event_task.result)
813+
else:
814+
yield context.call_activity("Escalate", None)
815+
```
816+
817+
To create the durable timer, call `context.create_timer`. The notification is received by `context.wait_for_external_event`. Then, `context.task_any` is called to decide whether to escalate (timeout happens first) or process the approval (the approval is received before timeout).
818+
702819
# [PowerShell](#tab/powershell)
703820

704821
```powershell
@@ -806,13 +923,33 @@ module.exports = async function (context) {
806923
# [Python](#tab/python)
807924

808925
```python
926+
import azure.functions as func
809927
import azure.durable_functions as df
810928

929+
myApp = df.DFApp(http_auth_level=func.AuthLevel.ANONYMOUS)
930+
931+
# An HTTP-Triggered Function with a Durable Functions Client binding
932+
@myApp.route(route="orchestrators/{functionName}")
933+
@myApp.durable_client_input(client_name="client")
934+
async def main(client):
935+
is_approved = True
936+
await client.raise_event(instance_id, "ApprovalEvent", is_approved)
937+
```
938+
811939

940+
# [Python (PM2)](#tab/python-v2)
941+
942+
```python
943+
import azure.functions as func
944+
import azure.durable_functions as df
945+
946+
myApp = df.DFApp(http_auth_level=func.AuthLevel.ANONYMOUS)
947+
948+
@myApp.route(route="orchestrators/{functionName}")
949+
@myApp.durable_client_input(client_name="client")
812950
async def main(client: str):
813-
durable_client = df.DurableOrchestrationClient(client)
814951
is_approved = True
815-
await durable_client.raise_event(instance_id, "ApprovalEvent", is_approved)
952+
await client.raise_event(instance_id, "ApprovalEvent", is_approved)
816953
```
817954

818955
# [PowerShell](#tab/powershell)
@@ -942,6 +1079,31 @@ def entity_function(context: df.DurableOrchestrationContext):
9421079
main = df.Entity.create(entity_function)
9431080
```
9441081

1082+
# [Python (PM2)](#tab/python-v2)
1083+
1084+
```python
1085+
import azure.functions as func
1086+
import azure.durable_functions as df
1087+
1088+
myApp = df.DFApp(http_auth_level=func.AuthLevel.ANONYMOUS)
1089+
1090+
@myApp.entity_trigger(context_name="context")
1091+
def entity_function(context: df.DurableOrchestrationContext):
1092+
1093+
current_value = context.get_state(lambda: 0)
1094+
operation = context.operation_name
1095+
if operation == "add":
1096+
amount = context.get_input()
1097+
current_value += amount
1098+
context.set_result(current_value)
1099+
elif operation == "reset":
1100+
current_value = 0
1101+
elif operation == "get":
1102+
context.set_result(current_value)
1103+
1104+
context.set_state(current_value)
1105+
```
1106+
9451107
# [PowerShell](#tab/powershell)
9461108

9471109
Durable entities are currently not supported in PowerShell.
@@ -996,14 +1158,29 @@ module.exports = async function (context) {
9961158
import azure.functions as func
9971159
import azure.durable_functions as df
9981160

999-
10001161
async def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
10011162
client = df.DurableOrchestrationClient(starter)
10021163
entity_id = df.EntityId("Counter", "myCounter")
10031164
instance_id = await client.signal_entity(entity_id, "add", 1)
10041165
return func.HttpResponse("Entity signaled")
10051166
```
10061167

1168+
# [Python (PM2)](#tab/python-v2)
1169+
1170+
```python
1171+
import azure.functions as func
1172+
import azure.durable_functions as df
1173+
1174+
myApp = df.DFApp(http_auth_level=func.AuthLevel.ANONYMOUS)
1175+
1176+
@myApp.route(route="orchestrators/{functionName}")
1177+
@myApp.durable_client_input(client_name="client")
1178+
async def main(req: func.HttpRequest, client) -> func.HttpResponse:
1179+
entity_id = df.EntityId("Counter", "myCounter")
1180+
instance_id = await client.signal_entity(entity_id, "add", 1)
1181+
return func.HttpResponse("Entity signaled")
1182+
```
1183+
10071184
# [PowerShell](#tab/powershell)
10081185

10091186
Durable entities are currently not supported in PowerShell.

0 commit comments

Comments
 (0)