Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions samples/durable-functions/python/hello-cities/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.venv/
__pycache__/
*.pyc
66 changes: 66 additions & 0 deletions samples/durable-functions/python/hello-cities/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Hello Cities — Durable Functions Python Quickstart

Python | Durable Functions

## Description

This quickstart demonstrates Durable Functions with Python (v2 programming model) using the Durable Task Scheduler backend. It includes two patterns:

1. **Function Chaining** — An orchestration that calls three "say hello" activities sequentially
2. **Fan-out/Fan-in** — An orchestration that greets multiple cities in parallel and aggregates results

## Prerequisites

1. [Python 3.9+](https://www.python.org/downloads/)
2. [Azure Functions Core Tools v4](https://learn.microsoft.com/azure/azure-functions/functions-run-local)
3. [Docker](https://www.docker.com/products/docker-desktop/) (for the emulator)

## Quick Run

1. Start the emulator:
```bash
docker run -d -p 8080:8080 -p 8082:8082 mcr.microsoft.com/dts/dts-emulator:latest
```

2. Create a virtual environment and install dependencies:
```bash
cd samples/durable-functions/python/hello-cities
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
pip install -r requirements.txt
```

3. Run the function app:
```bash
func start
```

4. Trigger the function chaining orchestration:
```bash
curl -X POST http://localhost:7071/api/StartChaining
```

5. Trigger the fan-out/fan-in orchestration:
```bash
curl -X POST http://localhost:7071/api/StartFanOutFanIn
```

6. View in the dashboard: http://localhost:8082

## Expected Output

The chaining orchestration greets Tokyo, Seattle, and London sequentially:
```json
["Hello Tokyo!", "Hello Seattle!", "Hello London!"]
```

The fan-out/fan-in orchestration greets all five cities in parallel and returns combined results:
```json
["Hello Tokyo!", "Hello Seattle!", "Hello London!", "Hello Paris!", "Hello Berlin!"]
```

## Learn More

- [Durable Functions Python API Reference](https://learn.microsoft.com/python/api/azure-functions-durable/azure.durable_functions)
- [Durable Functions Python Quickstart](https://learn.microsoft.com/azure/azure-functions/durable/quickstart-python-vscode)
- [Durable Task Scheduler Documentation](https://aka.ms/dts-documentation)
55 changes: 55 additions & 0 deletions samples/durable-functions/python/hello-cities/function_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import azure.functions as func
import azure.durable_functions as df
import logging

app = df.DFApp(http_auth_level=func.AuthLevel.ANONYMOUS)


@app.orchestration_trigger(context_name="context")
def chaining_orchestration(context: df.DurableOrchestrationContext):
"""Function chaining orchestration: calls activities sequentially."""
result1 = yield context.call_activity("say_hello", "Tokyo")
result2 = yield context.call_activity("say_hello", "Seattle")
result3 = yield context.call_activity("say_hello", "London")
return [result1, result2, result3]


@app.orchestration_trigger(context_name="context")
def fan_out_fan_in_orchestration(context: df.DurableOrchestrationContext):
"""Fan-out/Fan-in orchestration: calls activities in parallel."""
cities = ["Tokyo", "Seattle", "London", "Paris", "Berlin"]

# Fan-out: schedule all activities in parallel
parallel_tasks = []
for city in cities:
task = context.call_activity("say_hello", city)
parallel_tasks.append(task)

# Fan-in: wait for all to complete
results = yield context.task_all(parallel_tasks)
return results


@app.activity_trigger(input_name="city")
def say_hello(city: str) -> str:
"""Activity function that returns a greeting for a city."""
logging.info(f"Saying hello to {city}.")
return f"Hello {city}!"


@app.route(route="StartChaining", methods=["POST"])
@app.durable_client_input(client_name="client")
async def start_chaining(req: func.HttpRequest, client) -> func.HttpResponse:
"""HTTP trigger to start the function chaining orchestration."""
instance_id = await client.start_new("chaining_orchestration")
logging.info(f"Started chaining orchestration with ID = '{instance_id}'.")
return client.create_check_status_response(req, instance_id)


@app.route(route="StartFanOutFanIn", methods=["POST"])
@app.durable_client_input(client_name="client")
async def start_fan_out_fan_in(req: func.HttpRequest, client) -> func.HttpResponse:
"""HTTP trigger to start the fan-out/fan-in orchestration."""
instance_id = await client.start_new("fan_out_fan_in_orchestration")
logging.info(f"Started fan-out/fan-in orchestration with ID = '{instance_id}'.")
return client.create_check_status_response(req, instance_id)
21 changes: 21 additions & 0 deletions samples/durable-functions/python/hello-cities/host.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"version": "2.0",
"logging": {
"logLevel": {
"DurableTask.Core": "Warning"
}
},
"extensions": {
"durableTask": {
"hubName": "default",
"storageProvider": {
"type": "azureManaged",
"connectionStringName": "DURABLE_TASK_SCHEDULER_CONNECTION_STRING"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[4.*, 5.0.0)"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "python",
"DURABLE_TASK_SCHEDULER_CONNECTION_STRING": "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
azure-functions
azure-functions-durable
Loading