|
| 1 | +--- |
| 2 | +title: "Quickstart: Set a portable Durable Task SDK in your application to use Azure Functions Durable Task Scheduler (preview)" |
| 3 | +description: Learn how to configure an existing container app for the Azure Functions Durable Task Scheduler using the portable Durable Task SDKs and deploy using Azure Developer CLI. |
| 4 | +ms.topic: how-to |
| 5 | +ms.date: 04/29/2025 |
| 6 | +zone_pivot_groups: df-languages |
| 7 | +--- |
| 8 | + |
| 9 | +# Quickstart: Set a portable Durable Task SDK in your container app to use Azure Functions Durable Task Scheduler (preview) |
| 10 | + |
| 11 | +::: zone pivot="javascript" |
| 12 | + |
| 13 | +[!INCLUDE [preview-sample-limitations](./includes/preview-sample-limitations.md)] |
| 14 | + |
| 15 | +::: zone-end |
| 16 | + |
| 17 | +::: zone pivot="powershell" |
| 18 | + |
| 19 | +[!INCLUDE [preview-sample-limitations](./includes/preview-sample-limitations.md)] |
| 20 | + |
| 21 | +::: zone-end |
| 22 | + |
| 23 | +::: zone pivot="csharp,python,java" |
| 24 | + |
| 25 | +In this quickstart, you learn how to: |
| 26 | + |
| 27 | +> [!div class="checklist"] |
| 28 | +> |
| 29 | +> - Set up and run the Durable Task Scheduler emulator for local development. |
| 30 | +> - Run the worker and client projects. |
| 31 | +> - Check the Azure Container Apps logs. |
| 32 | +> - Review orchestration status and history via the Durable Task Scheduler dashboard. |
| 33 | +
|
| 34 | +## Prerequisites |
| 35 | + |
| 36 | +Before you begin: |
| 37 | + |
| 38 | +::: zone-end |
| 39 | + |
| 40 | +::: zone pivot="csharp" |
| 41 | + |
| 42 | +- Make sure you have [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0) or later. |
| 43 | +- Install [Docker](https://www.docker.com/products/docker-desktop/) for running the emulator. |
| 44 | +- Install [Azure Developer CLI](/azure/developer/azure-developer-cli/install-azd) |
| 45 | +- Clone the [Durable Task Scheduler GitHub repository](https://github.com/Azure-Samples/Durable-Task-Scheduler) to use the quickstart sample. |
| 46 | + |
| 47 | +::: zone-end |
| 48 | + |
| 49 | + |
| 50 | +::: zone pivot="python" |
| 51 | + |
| 52 | +- Make sure you have [Python 3.9+](https://www.python.org/downloads/) or later. |
| 53 | +- Install [Docker](https://www.docker.com/products/docker-desktop/) for running the emulator. |
| 54 | +- Install [Azure Developer CLI](/azure/developer/azure-developer-cli/install-azd) |
| 55 | +- Clone the [Durable Task Scheduler GitHub repository](https://github.com/Azure-Samples/Durable-Task-Scheduler) to use the quickstart sample. |
| 56 | + |
| 57 | +::: zone-end |
| 58 | + |
| 59 | +::: zone pivot="java" |
| 60 | + |
| 61 | +- Make sure you have [Java 8 or 11](https://www.java.com/en/download/). |
| 62 | +- Install [Docker](https://www.docker.com/products/docker-desktop/) for running the emulator. |
| 63 | +- Install [Azure Developer CLI](/azure/developer/azure-developer-cli/install-azd) |
| 64 | +- Clone the [Durable Task Scheduler GitHub repository](https://github.com/Azure-Samples/Durable-Task-Scheduler) to use the quickstart sample. |
| 65 | + |
| 66 | +::: zone-end |
| 67 | + |
| 68 | +::: zone pivot="csharp,python,java" |
| 69 | + |
| 70 | +## Prepare the project |
| 71 | + |
| 72 | +::: zone-end |
| 73 | + |
| 74 | +In a new terminal window, from the `Azure-Samples/Durable-Task-Scheduler` directory, navigate into the sample directory. |
| 75 | + |
| 76 | +::: zone pivot="csharp" |
| 77 | + |
| 78 | +```bash |
| 79 | +cd /samples/portable-sdks/dotnet/FunctionChaining |
| 80 | +``` |
| 81 | + |
| 82 | +::: zone-end |
| 83 | + |
| 84 | +::: zone pivot="python" |
| 85 | + |
| 86 | +```bash |
| 87 | +cd /samples/portable-sdks/python/FunctionChaining |
| 88 | +``` |
| 89 | + |
| 90 | +::: zone-end |
| 91 | + |
| 92 | +::: zone pivot="java" |
| 93 | + |
| 94 | +```bash |
| 95 | +cd /samples/portable-sdks/java/FunctionChaining |
| 96 | +``` |
| 97 | + |
| 98 | +::: zone-end |
| 99 | + |
| 100 | +::: zone pivot="csharp,python,java" |
| 101 | + |
| 102 | +## Deploy using Azure Developer CLI |
| 103 | + |
| 104 | +1. Run `azd up` to provision the infrastructure and deploy the application to Azure Container Apps in a single command. |
| 105 | + |
| 106 | + ```azdeveloper |
| 107 | + azd up |
| 108 | + ``` |
| 109 | + |
| 110 | +1. When prompted in the terminal, provide the following parameters. |
| 111 | + |
| 112 | + | Parameter | Description | |
| 113 | + | --------- | ----------- | |
| 114 | + | Environment Name | Prefix for the resource group created to hold all Azure resources. | |
| 115 | + | Azure Location | The Azure location for your resources. | |
| 116 | + | Azure Subscription | The Azure subscription for your resources. | |
| 117 | + |
| 118 | + This process may take some time to complete. As the `azd up` command completes, the CLI output displays two Azure portal links to monitor the deployment progress. The output also demonstrates how `azd up`: |
| 119 | + |
| 120 | + - Creates and configures all necessary Azure resources via the provided Bicep files in the `./infra` directory using `azd provision`. Once provisioned by Azure Developer CLI, you can access these resources via the Azure portal. The files that provision the Azure resources include: |
| 121 | + - `main.parameters.json` |
| 122 | + - `main.bicep` |
| 123 | + - An `app` resources directory organized by functionality |
| 124 | + - A `core` reference library that contains the Bicep modules used by the `azd` template |
| 125 | + - Deploys the code using `azd deploy` |
| 126 | + |
| 127 | + ### Expected output |
| 128 | + |
| 129 | + ```azdeveloper |
| 130 | + Packaging services (azd package) |
| 131 | +
|
| 132 | + (✓) Done: Packaging service client |
| 133 | + - Image Hash: {IMAGE_HASH} |
| 134 | + - Target Image: {TARGET_IMAGE} |
| 135 | +
|
| 136 | +
|
| 137 | + (✓) Done: Packaging service worker |
| 138 | + - Image Hash: {IMAGE_HASH} |
| 139 | + - Target Image: {TARGET_IMAGE} |
| 140 | +
|
| 141 | +
|
| 142 | + Provisioning Azure resources (azd provision) |
| 143 | + Provisioning Azure resources can take some time. |
| 144 | +
|
| 145 | + Subscription: SUBSCRIPTION_NAME (SUBSCRIPTION_ID) |
| 146 | + Location: West US 2 |
| 147 | +
|
| 148 | + You can view detailed progress in the Azure Portal: |
| 149 | + https://portal.azure.com/#view/HubsExtension/DeploymentDetailsBlade/~/overview/id/%2Fsubscriptions%SUBSCRIPTION_ID%2Fproviders%2FMicrosoft.Resources%2Fdeployments%2FCONTAINER_APP_ENVIRONMENT |
| 150 | +
|
| 151 | + (✓) Done: Resource group: GENERATED_RESOURCE_GROUP (1.385s) |
| 152 | + (✓) Done: Container Apps Environment: GENERATED_CONTAINER_APP_ENVIRONMENT (54.125s) |
| 153 | + (✓) Done: Container Registry: GENERATED_REGISTRY (1m27.747s) |
| 154 | + (✓) Done: Container App: SAMPLE_CLIENT_APP (21.39s) |
| 155 | + (✓) Done: Container App: SAMPLE_WORKER_APP (24.136s) |
| 156 | + |
| 157 | + Deploying services (azd deploy) |
| 158 | +
|
| 159 | + (✓) Done: Deploying service client |
| 160 | + - Endpoint: https://SAMPLE_CLIENT_APP.westus2.azurecontainerapps.io/ |
| 161 | +
|
| 162 | + (✓) Done: Deploying service worker |
| 163 | + - Endpoint: https://SAMPLE_WORKER_APP.westus2.azurecontainerapps.io/ |
| 164 | +
|
| 165 | +
|
| 166 | + SUCCESS: Your up workflow to provision and deploy to Azure completed in 10 minutes 34 seconds. ``` |
| 167 | +
|
| 168 | +## Confirm successful deployment |
| 169 | +
|
| 170 | +In the Azure portal, verify the client container app is publishing messages to the Azure Service Bus topic. |
| 171 | +
|
| 172 | +1. Copy the resource group name from the terminal output. |
| 173 | +
|
| 174 | +1. Sign in to the [Azure portal](https://portal.azure.com) and search for that resource group name. |
| 175 | +
|
| 176 | +1. From the resource group overview page, click on the client container app resource. |
| 177 | +
|
| 178 | +1. Select **Monitoring** > **Log stream**. |
| 179 | +
|
| 180 | +1. Confirm the client container is logging the function chaining tasks. |
| 181 | +
|
| 182 | + :::image type="content" source="media/quickstart-aca-azd-durable-task-sdk/client-app-log-stream.png" alt-text="Screenshot of the client container's log stream in the Azure portal."::: |
| 183 | +
|
| 184 | +1. Navigate back to the resource group page to select the `worker` container. |
| 185 | +
|
| 186 | +1. Select **Monitoring** > **Log stream**. |
| 187 | +
|
| 188 | +1. Confirm the client container is logging the function chaining tasks. |
| 189 | +
|
| 190 | + :::image type="content" source="media/quickstart-aca-azd-durable-task-sdk/worker-app-log-stream.png" alt-text="Screenshot of the worker container's log stream in the Azure portal."::: |
| 191 | +
|
| 192 | +::: zone-end |
| 193 | +
|
| 194 | +::: zone pivot="csharp,python,java" |
| 195 | +
|
| 196 | +## Understanding the code |
| 197 | +
|
| 198 | +::: zone-end |
| 199 | +
|
| 200 | +::: zone pivot="csharp" |
| 201 | +
|
| 202 | +### Worker Project |
| 203 | +
|
| 204 | +The Worker project contains: |
| 205 | +
|
| 206 | +- **GreetingOrchestration.cs**: Defines the orchestrator and activity functions in a single file |
| 207 | +- **Program.cs**: Sets up the worker host with proper connection string handling |
| 208 | +
|
| 209 | +#### Orchestration Implementation |
| 210 | +
|
| 211 | +The orchestration directly calls each activity in sequence using the standard `CallActivityAsync` method: |
| 212 | +
|
| 213 | +```csharp |
| 214 | +public override async Task<string> RunAsync(TaskOrchestrationContext context, string name) |
| 215 | +{ |
| 216 | + // Step 1: Say hello to the person |
| 217 | + string greeting = await context.CallActivityAsync<string>(nameof(SayHelloActivity), name); |
| 218 | + |
| 219 | + // Step 2: Process the greeting |
| 220 | + string processedGreeting = await context.CallActivityAsync<string>(nameof(ProcessGreetingActivity), greeting); |
| 221 | + |
| 222 | + // Step 3: Finalize the response |
| 223 | + string finalResponse = await context.CallActivityAsync<string>(nameof(FinalizeResponseActivity), processedGreeting); |
| 224 | + |
| 225 | + return finalResponse; |
| 226 | +} |
| 227 | +``` |
| 228 | + |
| 229 | +Each activity is implemented as a separate class decorated with the `[DurableTask]` attribute: |
| 230 | + |
| 231 | +```csharp |
| 232 | +[DurableTask] |
| 233 | +public class SayHelloActivity : TaskActivity<string, string> |
| 234 | +{ |
| 235 | + // Implementation details |
| 236 | +} |
| 237 | +``` |
| 238 | + |
| 239 | +The worker uses Microsoft.Extensions.Hosting for proper lifecycle management: |
| 240 | +```csharp |
| 241 | +var builder = Host.CreateApplicationBuilder(); |
| 242 | +builder.Services.AddDurableTaskWorker() |
| 243 | + .AddTasks(registry => { |
| 244 | + registry.AddAllGeneratedTasks(); |
| 245 | + }) |
| 246 | + .UseDurableTaskScheduler(connectionString); |
| 247 | +var host = builder.Build(); |
| 248 | +await host.StartAsync(); |
| 249 | +``` |
| 250 | + |
| 251 | +### Client Project |
| 252 | + |
| 253 | +The Client project: |
| 254 | + |
| 255 | +- Uses the same connection string logic as the worker |
| 256 | +- Schedules an orchestration instance with a name input |
| 257 | +- Waits for the orchestration to complete and displays the result |
| 258 | +- Uses WaitForInstanceCompletionAsync for efficient polling |
| 259 | + |
| 260 | +```csharp |
| 261 | +var instance = await client.WaitForInstanceCompletionAsync( |
| 262 | + instanceId, |
| 263 | + getInputsAndOutputs: true, |
| 264 | + cts.Token); |
| 265 | +``` |
| 266 | + |
| 267 | +::: zone-end |
| 268 | + |
| 269 | +::: zone pivot="python" |
| 270 | + |
| 271 | +### Worker Project |
| 272 | + |
| 273 | +The Worker project contains: |
| 274 | + |
| 275 | +- ****: Defines the orchestrator and activity functions in a single file |
| 276 | +- ****: Sets up the worker host with proper connection string handling |
| 277 | + |
| 278 | +#### Orchestration Implementation |
| 279 | + |
| 280 | +The orchestration directly calls each activity in sequence using the standard `CallActivityAsync` method: |
| 281 | + |
| 282 | +```python |
| 283 | + |
| 284 | +``` |
| 285 | + |
| 286 | +Each activity is implemented as a separate class decorated with the `[DurableTask]` attribute: |
| 287 | + |
| 288 | +```python |
| 289 | + |
| 290 | +``` |
| 291 | + |
| 292 | +The worker uses Microsoft.Extensions.Hosting for proper lifecycle management: |
| 293 | + |
| 294 | +```python |
| 295 | + |
| 296 | +``` |
| 297 | + |
| 298 | +### Client Project |
| 299 | + |
| 300 | +The Client project: |
| 301 | + |
| 302 | +- Uses the same connection string logic as the worker |
| 303 | +- Schedules an orchestration instance with a name input |
| 304 | +- Waits for the orchestration to complete and displays the result |
| 305 | +- Uses WaitForInstanceCompletionAsync for efficient polling |
| 306 | + |
| 307 | +```python |
| 308 | + |
| 309 | +``` |
| 310 | + |
| 311 | + |
| 312 | +::: zone-end |
| 313 | + |
| 314 | +::: zone pivot="java" |
| 315 | + |
| 316 | +### Worker Project |
| 317 | + |
| 318 | +The Worker project contains: |
| 319 | + |
| 320 | +- ****: Defines the orchestrator and activity functions in a single file |
| 321 | +- ****: Sets up the worker host with proper connection string handling |
| 322 | + |
| 323 | +#### Orchestration Implementation |
| 324 | + |
| 325 | +The orchestration directly calls each activity in sequence using the standard `CallActivityAsync` method: |
| 326 | + |
| 327 | +```java |
| 328 | + |
| 329 | +``` |
| 330 | + |
| 331 | +Each activity is implemented as a separate class decorated with the `[DurableTask]` attribute: |
| 332 | + |
| 333 | +```java |
| 334 | + |
| 335 | +``` |
| 336 | + |
| 337 | +The worker uses Microsoft.Extensions.Hosting for proper lifecycle management: |
| 338 | + |
| 339 | +```java |
| 340 | + |
| 341 | +``` |
| 342 | + |
| 343 | +### Client Project |
| 344 | + |
| 345 | +The Client project: |
| 346 | + |
| 347 | +- Uses the same connection string logic as the worker |
| 348 | +- Schedules an orchestration instance with a name input |
| 349 | +- Waits for the orchestration to complete and displays the result |
| 350 | +- Uses WaitForInstanceCompletionAsync for efficient polling |
| 351 | + |
| 352 | +```java |
| 353 | + |
| 354 | +``` |
| 355 | + |
| 356 | +::: zone-end |
| 357 | + |
| 358 | +## Next steps |
| 359 | + |
| 360 | +Need |
0 commit comments