Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Prepare Azure environments for new workloads—subscriptions, networking, identity, and landing zones
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/services/durable-task-scheduler/dotnet.md
1# Durable Task Scheduler — .NET23## Learn More45- [Durable Task Scheduler documentation](https://learn.microsoft.com/azure/durable-task-scheduler/)6- [Durable Functions .NET isolated worker guide](https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-dotnet-isolated-overview)78## Durable Functions Setup910### Required NuGet Packages1112```xml13<ItemGroup>14<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.14.1" />15<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask.AzureManaged" Version="1.4.0" />16<PackageReference Include="Azure.Identity" Version="1.17.1" />17</ItemGroup>18```1920> **💡 Finding latest versions**: Search [nuget.org](https://www.nuget.org/) for each package name to find the current stable version. Look for the `Microsoft.Azure.Functions.Worker.Extensions.DurableTask` and `Microsoft.Azure.Functions.Worker.Extensions.DurableTask.AzureManaged` packages.2122### host.json2324```json25{26"version": "2.0",27"extensions": {28"durableTask": {29"storageProvider": {30"type": "azureManaged",31"connectionStringName": "DURABLE_TASK_SCHEDULER_CONNECTION_STRING"32},33"hubName": "default"34}35}36}37```3839> **💡 NOTE**: .NET isolated uses the `DurableTask.AzureManaged` NuGet package, which registers the `azureManaged` storage provider type. Other runtimes (Python, Java, JavaScript) use extension bundles and require `durabletask-scheduler` instead — see the respective language files. All runtimes use the same `DURABLE_TASK_SCHEDULER_CONNECTION_STRING` environment variable.4041### local.settings.json4243```json44{45"IsEncrypted": false,46"Values": {47"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",48"AzureWebJobsStorage": "UseDevelopmentStorage=true",49"DURABLE_TASK_SCHEDULER_CONNECTION_STRING": "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None"50}51}52```5354## Minimal Example5556```csharp57using Microsoft.Azure.Functions.Worker;58using Microsoft.DurableTask;59using Microsoft.DurableTask.Client;6061public static class DurableFunctionsApp62{63[Function("HttpStart")]64public static async Task<HttpResponseData> HttpStart(65[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,66[DurableClient] DurableTaskClient client)67{68string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(nameof(MyOrchestration));69return await client.CreateCheckStatusResponseAsync(req, instanceId);70}7172[Function(nameof(MyOrchestration))]73public static async Task<string> MyOrchestration([OrchestrationTrigger] TaskOrchestrationContext context)74{75var result1 = await context.CallActivityAsync<string>(nameof(SayHello), "Tokyo");76var result2 = await context.CallActivityAsync<string>(nameof(SayHello), "Seattle");77return $"{result1}, {result2}";78}7980[Function(nameof(SayHello))]81public static string SayHello([ActivityTrigger] string name) => $"Hello {name}!";82}83```8485## Workflow Patterns8687### Fan-Out/Fan-In8889```csharp90[Function(nameof(FanOutFanIn))]91public static async Task<string[]> FanOutFanIn([OrchestrationTrigger] TaskOrchestrationContext context)92{93string[] cities = { "Tokyo", "Seattle", "London", "Paris", "Berlin" };9495// Fan-out: schedule all in parallel96var tasks = cities.Select(city => context.CallActivityAsync<string>(nameof(SayHello), city));9798// Fan-in: wait for all99return await Task.WhenAll(tasks);100}101```102103### Human Interaction104105```csharp106[Function(nameof(ApprovalWorkflow))]107public static async Task<string> ApprovalWorkflow([OrchestrationTrigger] TaskOrchestrationContext context)108{109await context.CallActivityAsync(nameof(SendApprovalRequest), context.GetInput<string>());110111// Wait for approval event with timeout112using var cts = new CancellationTokenSource();113var approvalTask = context.WaitForExternalEvent<bool>("ApprovalEvent");114var timeoutTask = context.CreateTimer(context.CurrentUtcDateTime.AddDays(3), cts.Token);115116var winner = await Task.WhenAny(approvalTask, timeoutTask);117118if (winner == approvalTask)119{120cts.Cancel();121return await approvalTask ? "Approved" : "Rejected";122}123return "Timed out";124}125```126127## Orchestration Determinism128129| ❌ NEVER | ✅ ALWAYS USE |130|----------|--------------|131| `DateTime.Now` | `context.CurrentUtcDateTime` |132| `Guid.NewGuid()` | `context.NewGuid()` |133| `Random` | Pass random values from activities |134| `Task.Delay()`, `Thread.Sleep()` | `context.CreateTimer()` |135| Direct I/O, HTTP, database | `context.CallActivityAsync()` |136137### Replay-Safe Logging138139```csharp140[Function(nameof(MyOrchestration))]141public static async Task<string> MyOrchestration([OrchestrationTrigger] TaskOrchestrationContext context)142{143ILogger logger = context.CreateReplaySafeLogger(nameof(MyOrchestration));144logger.LogInformation("Started"); // Only logs once, not on replay145return await context.CallActivityAsync<string>(nameof(MyActivity), "input");146}147```148149## Error Handling & Retry150151```csharp152var retryOptions = new TaskOptions153{154Retry = new RetryPolicy(155maxNumberOfAttempts: 3,156firstRetryInterval: TimeSpan.FromSeconds(5),157backoffCoefficient: 2.0,158maxRetryInterval: TimeSpan.FromMinutes(1))159};160161var input = context.GetInput<string>();162163try164{165await context.CallActivityAsync<string>(nameof(UnreliableService), input, retryOptions);166}167catch (TaskFailedException ex)168{169context.SetCustomStatus(new { Error = ex.Message });170await context.CallActivityAsync(nameof(CompensationActivity), input);171}172```173174## Durable Task SDK (Non-Functions)175176For applications running outside Azure Functions (containers, VMs, Azure Container Apps, Azure Kubernetes Service):177178```csharp179var connectionString = "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None";180181// Worker182builder.Services.AddDurableTaskWorker()183.AddTasks(registry => registry.AddAllGeneratedTasks())184.UseDurableTaskScheduler(connectionString);185186// Client187var client = DurableTaskClientBuilder.UseDurableTaskScheduler(connectionString).Build();188string instanceId = await client.ScheduleNewOrchestrationInstanceAsync("MyOrchestration", input);189```190191