### Full Durable Task Framework OpenTelemetry Example Source: https://github.com/azure/durabletask/blob/main/docs/telemetry/distributed-tracing.md A comprehensive example demonstrating the setup of OpenTelemetry with Durable Task Framework, including worker and client configuration. Ensure you have the necessary connection string and logger factory configured. ```csharp using OpenTelemetry; using OpenTelemetry.Trace; using DurableTask.Core; using DurableTask.AzureStorage; // Configure OpenTelemetry using var tracerProvider = Sdk.CreateTracerProviderBuilder() .AddSource("DurableTask.Core") .AddConsoleExporter() .Build(); // Create logger factory using ILoggerFactory loggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); builder.SetMinimumLevel(LogLevel.Information); }); // Set up DTFx var settings = new AzureStorageOrchestrationServiceSettings { TaskHubName = "MyTaskHub", StorageAccountClientProvider = new StorageAccountClientProvider(connectionString), LoggerFactory = loggerFactory }; var service = new AzureStorageOrchestrationService(settings); await service.CreateIfNotExistsAsync(); var worker = new TaskHubWorker(service, loggerFactory); worker.AddTaskOrchestrations(typeof(MyOrchestration)); worker.AddTaskActivities(typeof(MyActivity)); await worker.StartAsync(); var client = new TaskHubClient(service, loggerFactory: loggerFactory); var instance = await client.CreateOrchestrationInstanceAsync( typeof(MyOrchestration), "input"); await client.WaitForOrchestrationAsync(instance, TimeSpan.FromMinutes(1)); await worker.StopAsync(); ``` -------------------------------- ### Install DTFx NuGet packages Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/quickstart.md Add the core framework and in-memory emulator packages to the project. ```bash dotnet add package Microsoft.Azure.DurableTask.Core dotnet add package Microsoft.Azure.DurableTask.Emulator ``` -------------------------------- ### Side-by-Side Versioning: Starting New Instances Source: https://github.com/azure/durabletask/blob/main/docs/features/versioning.md After registering multiple versions of an orchestration, new instances can be started with a specific version by providing the version string during the `CreateOrchestrationInstanceAsync` call. This string must match the version used during registration. ```csharp // Start with specific version var instance = await client.CreateOrchestrationInstanceAsync( "OrderOrchestration", "V2", // Version string must match registration input); ``` -------------------------------- ### Install OpenTelemetry Packages Source: https://github.com/azure/durabletask/blob/main/docs/telemetry/distributed-tracing.md Install the necessary OpenTelemetry packages using the .NET CLI. This includes the core OpenTelemetry library and a console exporter for basic output. ```bash dotnet add package OpenTelemetry dotnet add package OpenTelemetry.Exporter.Console # Or your preferred exporter ``` -------------------------------- ### Add Emulator Backend for Local Development Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/installation.md Install the emulator backend package for local development and testing without external dependencies. ```bash dotnet add package Microsoft.Azure.DurableTask.Emulator ``` -------------------------------- ### Install Application Insights Packages Source: https://github.com/azure/durabletask/blob/main/docs/telemetry/distributed-tracing.md Install the necessary NuGet packages for Application Insights integration with Durable Task. ```bash dotnet add package Microsoft.Azure.DurableTask.ApplicationInsights dotnet add package Microsoft.ApplicationInsights ``` -------------------------------- ### Start Orchestrations from Client Source: https://github.com/azure/durabletask/blob/main/docs/concepts/orchestrations.md Initiate new orchestration instances using the TaskHubClient, supporting auto-generated IDs, custom IDs, or scheduled start times. ```csharp var client = new TaskHubClient(service, loggerFactory: loggerFactory); // Start with auto-generated instance ID var instance = await client.CreateOrchestrationInstanceAsync( typeof(OrderProcessingOrchestration), new OrderInput { OrderId = "12345" }); // Start with custom instance ID var instance = await client.CreateOrchestrationInstanceAsync( typeof(OrderProcessingOrchestration), instanceId: "order-12345", input: new OrderInput { OrderId = "12345" }); // Start at a scheduled time var instance = await client.CreateScheduledOrchestrationInstanceAsync( typeof(OrderProcessingOrchestration), instanceId: "scheduled-order", input: new OrderInput { OrderId = "12345" }, startAt: DateTime.UtcNow.AddHours(1)); ``` -------------------------------- ### Install Service Fabric Provider Source: https://github.com/azure/durabletask/blob/main/docs/providers/service-fabric.md Add the Service Fabric provider package to your project using the .NET CLI. ```bash dotnet add package Microsoft.Azure.DurableTask.AzureServiceFabric ``` -------------------------------- ### Manual Service Fabric Provider Setup with Factory Source: https://github.com/azure/durabletask/blob/main/docs/providers/service-fabric.md Use `FabricOrchestrationProviderFactory` for advanced configuration and control over the Service Fabric provider setup. This allows for custom `StateManager` and `LoggerFactory` configurations. ```csharp using DurableTask.AzureServiceFabric; using DurableTask.Core; using Microsoft.ServiceFabric.Services.Runtime; public class DurableTaskService : StatefulService { private FabricOrchestrationProvider provider; private TaskHubWorker worker; public DurableTaskService(StatefulServiceContext context) : base(context) { } protected override async Task RunAsync(CancellationToken cancellationToken) { var settings = new FabricOrchestrationProviderSettings(); var factory = new FabricOrchestrationProviderFactory( this.StateManager, settings); provider = factory.CreateProvider(); worker = new TaskHubWorker(provider.OrchestrationService, settings.LoggerFactory); worker.AddTaskOrchestrations(typeof(MyOrchestration)); worker.AddTaskActivities(typeof(MyActivity)); await worker.StartAsync(); try { await Task.Delay(Timeout.Infinite, cancellationToken); } finally { await worker.StopAsync(); provider.Dispose(); } } } ``` -------------------------------- ### User-Assigned Managed Identity Example Source: https://github.com/azure/durabletask/blob/main/docs/providers/durable-task-scheduler.md Example connection string for using a user-assigned managed identity. Ensure the ClientId is correctly specified. ```text Endpoint=https://myscheduler.westus3.durabletask.io;TaskHub=default;Authentication=ManagedIdentity;ClientId=00000000-0000-0000-0000-000000000000 ``` -------------------------------- ### ContinueAsNew with Version 1 Source: https://github.com/azure/durabletask/wiki/Orchestration-Versioning Example of how ContinueAsNew was used to schedule the next generation of an orchestration with version '1'. ```csharp Context.ContinueAsNew("1", input); ``` -------------------------------- ### Durable Task Scheduler Core Code Sample Source: https://github.com/azure/durabletask/blob/main/docs/providers/durable-task-scheduler.md This C# code demonstrates setting up the Durable Task Scheduler service, configuring a worker with orchestrations and activities, starting the worker, creating a client, starting an orchestration, waiting for its completion, and cleaning up resources. ```csharp using DurableTask.Core; using Microsoft.DurableTask.AzureManagedBackend; using Microsoft.Extensions.Logging; // Get connection string from environment // Expected format: "Endpoint=https://;Authentication=;TaskHub=" string? connectionString = Environment.GetEnvironmentVariable("DTS_CONNECTION_STRING"); if (string.IsNullOrWhiteSpace(connectionString)) { Console.Error.WriteLine("An environment variable named DTS_CONNECTION_STRING is required."); return; } // Configure logging ILoggerFactory loggerFactory = LoggerFactory.Create(builder => builder.AddSimpleConsole(options => { options.SingleLine = true; options.UseUtcTimestamp = true; options.TimestampFormat = "yyyy-MM-ddTHH:mm:ss.fffZ "; })); // Create the orchestration service for Durable Task Scheduler AzureManagedOrchestrationService service = new( AzureManagedOrchestrationServiceOptions.FromConnectionString(connectionString), loggerFactory); // Create and configure the worker TaskHubWorker worker = new(service, loggerFactory); worker.AddTaskOrchestrations(typeof(HelloWorldOrchestration)); worker.AddTaskActivities(typeof(HelloActivity)); // Start the worker await worker.StartAsync(); // Create a client and start an orchestration TaskHubClient client = new(service, null, loggerFactory); OrchestrationInstance instance = await client.CreateOrchestrationInstanceAsync( orchestrationType: typeof(HelloWorldOrchestration), input: null); Console.WriteLine($"Started orchestration with ID = '{instance.InstanceId}'"); // Wait for completion OrchestrationState state = await client.WaitForOrchestrationAsync( instance, TimeSpan.FromMinutes(1)); Console.WriteLine($"Orchestration completed with status: {state.OrchestrationStatus}"); Console.WriteLine($"Output: {state.Output}"); // Clean up await worker.StopAsync(); service.Dispose(); ``` -------------------------------- ### Basic Application Insights Setup with DI Source: https://github.com/azure/durabletask/blob/main/docs/telemetry/application-insights.md Configure Application Insights and the DurableTask telemetry module using Dependency Injection in a .NET application. ```csharp using Microsoft.ApplicationInsights; using Microsoft.ApplicationInsights.Extensibility; using Microsoft.Azure.DurableTask.ApplicationInsights; using Microsoft.Extensions.DependencyInjection; var services = new ServiceCollection(); // Add Application Insights services.AddApplicationInsightsTelemetryWorkerService(options => { options.ConnectionString = "InstrumentationKey=your-key;..."; }); // Add DurableTask telemetry module for distributed tracing services.TryAddEnumerable( ServiceDescriptor.Singleton()); var serviceProvider = services.BuildServiceProvider(); ``` -------------------------------- ### Add Azure Storage Backend Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/installation.md Install the Azure Storage backend provider for self-managed deployments using Azure Queues, Tables, and Blobs. ```bash dotnet add package Microsoft.Azure.DurableTask.AzureStorage ``` -------------------------------- ### Start Sub-Orchestration with Custom Instance ID Source: https://github.com/azure/durabletask/blob/main/docs/features/sub-orchestrations.md Starts a sub-orchestration using a custom instance ID for easier identification and management. This is useful for scenarios where you need to reference a specific child orchestration run. ```csharp var result = await context.CreateSubOrchestrationInstance( typeof(ShippingOrchestration), instanceId: $"shipping-{input.OrderId}", // Custom ID input: input.ShippingData); ``` -------------------------------- ### Example Azure Storage Configuration with Performance Tuning Source: https://github.com/azure/durabletask/blob/main/docs/providers/azure-storage.md Demonstrates advanced configuration for the Azure Storage provider, including performance tuning parameters and lease settings for partition management. ```csharp var settings = new AzureStorageOrchestrationServiceSettings { StorageConnectionString = connectionString, TaskHubName = "MyTaskHub", // Performance tuning PartitionCount = 8, ControlQueueBufferThreshold = 128, MaxConcurrentTaskOrchestrationWorkItems = 200, MaxConcurrentTaskActivityWorkItems = 200, // Lease settings LeaseInterval = TimeSpan.FromSeconds(30), LeaseRenewInterval = TimeSpan.FromSeconds(10) }; ``` -------------------------------- ### Basic Service Fabric Provider Setup Source: https://github.com/azure/durabletask/blob/main/docs/providers/service-fabric.md Configure the Service Fabric provider using `TaskHubStatefulService` and `TaskHubProxyListener`. This is the recommended approach for most Service Fabric applications. ```csharp using DurableTask.AzureServiceFabric; using DurableTask.AzureServiceFabric.Service; using DurableTask.Core; using Microsoft.ServiceFabric.Services.Runtime; // In Program.cs ServiceRuntime.RegisterServiceAsync("StatefulServiceType", context => { var settings = new FabricOrchestrationProviderSettings(); var listener = new TaskHubProxyListener( settings, RegisterOrchestrations); return new TaskHubStatefulService(context, new[] { listener }); }).GetAwaiter().GetResult(); void RegisterOrchestrations(TaskHubWorker worker) { worker.AddTaskOrchestrations(typeof(MyOrchestration)); worker.AddTaskActivities(typeof(MyActivity)); } ``` -------------------------------- ### Add Durable Task Scheduler Backend Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/installation.md Install the recommended Durable Task Scheduler backend for new projects, offering a fully managed solution. ```bash dotnet add package Microsoft.DurableTask.AzureManagedBackend ``` -------------------------------- ### Create Orchestration with Default Version Source: https://github.com/azure/durabletask/blob/main/docs/features/versioning.md Demonstrates starting a new orchestration that will automatically be stamped with the worker's default version if no explicit version is provided. ```csharp // This orchestration will be created with version "2.0" (from VersioningSettings) var instance = await client.CreateOrchestrationInstanceAsync( typeof(OrderOrchestration), input); ``` -------------------------------- ### ContinueAsNew with Version 2 Source: https://github.com/azure/durabletask/wiki/Orchestration-Versioning Example of how ContinueAsNew is modified to schedule the next generation of an orchestration with version '2', facilitating an upgrade. ```csharp Context.ContinueAsNew("2", input); ``` -------------------------------- ### Add Azure Service Bus Backend Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/installation.md Install the Azure Service Bus backend provider for deployments leveraging Azure Service Bus for messaging. ```bash dotnet add package Microsoft.Azure.DurableTask.ServiceBus ``` -------------------------------- ### Add Core DTFx Package Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/installation.md Install the essential Microsoft.Azure.DurableTask.Core package, required for all DTFx applications. ```bash dotnet add package Microsoft.Azure.DurableTask.Core ``` -------------------------------- ### Structured Logging Example Source: https://github.com/azure/durabletask/blob/main/docs/telemetry/logging.md Use structured logging with named parameters for better readability and searchability. Avoid string concatenation for log messages. ```csharp // ✅ Good - structured with context _logger.LogInformation( "Processing order {OrderId} for customer {CustomerId} in orchestration {InstanceId}", input.OrderId, input.CustomerId, context.OrchestrationInstance.InstanceId); // ❌ Bad - string concatenation, no structure _logger.LogInformation( "Processing order " + input.OrderId + " for customer " + input.CustomerId); ``` -------------------------------- ### Start a Task Hub Worker Source: https://github.com/azure/durabletask/blob/main/docs/providers/azure-storage.md Connect multiple workers to the same task hub for horizontal scaling. Ensure you have a logger factory configured. ```csharp var service = new AzureStorageOrchestrationService(settings); var worker = new TaskHubWorker(service, loggerFactory); await worker.StartAsync(); ``` -------------------------------- ### Add Azure Service Fabric Backend Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/installation.md Install the Azure Service Fabric backend provider for applications running on Azure Service Fabric. ```bash dotnet add package Microsoft.Azure.DurableTask.AzureServiceFabric ``` -------------------------------- ### Orchestration Middleware for Authentication/Authorization Source: https://github.com/azure/durabletask/blob/main/docs/advanced/middleware.md Implement middleware to handle authentication and authorization for orchestrations. This example checks for a user ID and authorization before allowing execution. ```csharp worker.AddOrchestrationDispatcherMiddleware(async (context, next) => { var executionContext = context.GetProperty(); string? userId = null; executionContext?.OrchestrationTags?.TryGetValue("UserId", out userId); if (string.IsNullOrEmpty(userId) || !await authService.IsAuthorizedAsync(userId, "ExecuteOrchestration")) { // Don't throw - that would cause retries. Instead, fail the orchestration explicitly. context.SetProperty(new OrchestratorExecutionResult { Actions = new[] { new OrchestrationCompleteOrchestratorAction { OrchestrationStatus = OrchestrationStatus.Failed, Result = $"User {userId ?? "unknown"} is not authorized to execute orchestrations", FailureDetails = new FailureDetails( errorType: "UnauthorizedAccessException", errorMessage: $"User {userId ?? "unknown"} is not authorized", stackTrace: null, innerFailure: null, isNonRetriable: true) } } }); return; // Don't call next() } await next(); }); ``` -------------------------------- ### Basic Azure Storage Configuration Source: https://github.com/azure/durabletask/blob/main/docs/providers/azure-storage.md Configure the Azure Storage provider with a connection string and task hub name. This setup requires manual creation of the service and worker. ```csharp using DurableTask.AzureStorage; using DurableTask.Core; using Microsoft.Extensions.Logging; using ILoggerFactory loggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); builder.SetMinimumLevel(LogLevel.Information); }); var settings = new AzureStorageOrchestrationServiceSettings { StorageConnectionString = "DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;", TaskHubName = "MyTaskHub", LoggerFactory = loggerFactory }; var service = new AzureStorageOrchestrationService(settings); await service.CreateIfNotExistsAsync(); var worker = new TaskHubWorker(service, loggerFactory); var client = new TaskHubClient(service, loggerFactory: loggerFactory); ``` -------------------------------- ### Start a Sub-Orchestration and Wait for Result Source: https://github.com/azure/durabletask/blob/main/docs/features/sub-orchestrations.md Initiates a sub-orchestration and retrieves its result. Ensure the target orchestration type and input data are correctly provided. ```csharp public override async Task RunTask( OrchestrationContext context, OrderInput input) { // Start a sub-orchestration and wait for result var paymentResult = await context.CreateSubOrchestrationInstance( typeof(PaymentOrchestration), input.PaymentData); return new OrderResult { PaymentId = paymentResult.TransactionId }; } ``` -------------------------------- ### Connect to Local Emulator Source: https://github.com/azure/durabletask/blob/main/docs/providers/durable-task-scheduler.md Instantiate the Durable Task Scheduler service using a connection string pointing to the local emulator. This setup is suitable for local development and testing. ```csharp var connectionString = "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None"; var service = new AzureManagedOrchestrationService( AzureManagedOrchestrationServiceOptions.FromConnectionString(connectionString), loggerFactory); ``` -------------------------------- ### TaskHubClient Operations for Orchestration Management Source: https://github.com/azure/durabletask/blob/main/docs/concepts/core-concepts.md Shows how to use the TaskHubClient to start, query, send events to, wait for, and terminate orchestration instances. Requires an initialized orchestration service. ```csharp var orchestrationService = GetSelectedOrchestrationService(); var client = new TaskHubClient(orchestrationService, loggerFactory: loggerFactory); // Start a new orchestration var instance = await client.CreateOrchestrationInstanceAsync( typeof(MyOrchestration), instanceId: "order-123", input: new OrderData { ... }); // Query status var state = await client.GetOrchestrationStateAsync(instance); // Send an event await client.RaiseEventAsync(instance, "ApprovalReceived", approvalData); // Wait for completion var result = await client.WaitForOrchestrationAsync(instance, timeout); // Terminate await client.TerminateInstanceAsync(instance, "Cancelled by user"); ``` -------------------------------- ### Example Log Output Source: https://github.com/azure/durabletask/blob/main/docs/telemetry/logging.md Illustrates typical log messages generated by the Durable Task Framework, showing information about worker status, orchestration scheduling, activity execution, and completion. ```text info: DurableTask.Core[10] Durable task hub worker is starting info: DurableTask.Core[40] Scheduling orchestration 'MyOrchestration' with instance ID = 'abc123' info: DurableTask.Core[51] abc123: Executing 'MyOrchestration' orchestration logic info: DurableTask.Core[46] abc123: Scheduling activity [MyActivity#0] info: DurableTask.Core[60] abc123: Starting task activity [MyActivity#0] info: DurableTask.Core[61] abc123: Task activity [MyActivity#0] completed successfully info: DurableTask.Core[49] abc123: Orchestration completed with status 'Completed' ``` -------------------------------- ### Implement an Activity Unit of Work Source: https://github.com/azure/durabletask/blob/main/docs/concepts/core-concepts.md Create a C# class that inherits from AsyncTaskActivity to define a unit of work that can be scheduled by an orchestration. This example demonstrates calling an external service. ```csharp public class ProcessPaymentActivity : AsyncTaskActivity { protected override async Task ExecuteAsync( TaskContext context, PaymentInput input) { // Actual work here - call payment API, etc. var result = await PaymentService.ProcessAsync(input); return result; } } ``` -------------------------------- ### Initialize a new .NET console project Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/quickstart.md Create a new console application directory and project file. ```bash dotnet new console -n HelloDurableTask cd HelloDurableTask ``` -------------------------------- ### Run the application Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/quickstart.md Execute the application and view the expected output. ```bash dotnet run ``` ```text Worker started. Started orchestration: Result: "Hello, World!" Status: Completed ``` -------------------------------- ### Use Orchestration GUIDs Source: https://github.com/azure/durabletask/blob/main/docs/concepts/deterministic-constraints.md Generating new GUIDs directly inside an orchestration leads to inconsistencies. Use the context-provided method or fetch IDs from activities. ```csharp // ❌ WRONG - Different GUID on replay var id = Guid.NewGuid().ToString(); await context.ScheduleTask(typeof(ProcessActivity), id); // ✅ CORRECT - Use orchestration's NewGuid var id = context.NewGuid().ToString(); await context.ScheduleTask(typeof(ProcessActivity), id); // ✅ Also correct - Get from activity var id = await context.ScheduleTask(typeof(GenerateIdActivity), null); ``` -------------------------------- ### TaskHubWorker Lifecycle and Handler Registration Source: https://github.com/azure/durabletask/blob/main/docs/concepts/core-concepts.md Demonstrates how to create, register handlers for, and start a TaskHubWorker. Ensure all necessary orchestration and activity types are registered before starting. ```csharp var orchestrationService = GetSelectedOrchestrationService(); var worker = new TaskHubWorker(orchestrationService, loggerFactory); // Register handlers worker.AddTaskOrchestrations(typeof(MyOrchestration)); worker.AddTaskActivities(typeof(MyActivity)); // Start processing await worker.StartAsync(); // ... application runs ... // Graceful shutdown await worker.StopAsync(); ``` -------------------------------- ### Manage Task Hub and Orchestrations Source: https://github.com/azure/durabletask/blob/main/samples/DurableTask.Samples/README.md Commands to initialize the task hub and execute specific orchestration samples. ```bash DurableTask.Samples.exe -c ``` ```bash DurableTask.Samples.exe -s [-p ] ``` -------------------------------- ### Version Comparison Examples Source: https://github.com/azure/durabletask/blob/main/docs/features/versioning.md Illustrates how versions are compared using numeric comparison for System.Version-parsable strings and case-insensitive string comparison otherwise. Empty versions are treated as less than any defined version. ```csharp // Version comparison examples VersioningSettings.CompareVersions("1.0.0", "1.0.0"); // Returns 0 (equal) VersioningSettings.CompareVersions("2.0.0", "1.0.0"); // Returns 1 (greater) VersioningSettings.CompareVersions("1.0.0", "2.0.0"); // Returns -1 (less) VersioningSettings.CompareVersions("", "1.0.0"); // Returns -1 (empty < defined) ``` -------------------------------- ### Initialize Emulator Service and Worker Source: https://github.com/azure/durabletask/blob/main/docs/providers/emulator.md Set up the in-memory LocalOrchestrationService, TaskHubWorker, and TaskHubClient for local development. ```csharp using DurableTask.Core; using DurableTask.Emulator; using Microsoft.Extensions.Logging; using ILoggerFactory loggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); builder.SetMinimumLevel(LogLevel.Information); }); // Create in-memory service var service = new LocalOrchestrationService(); // Create worker and client var worker = new TaskHubWorker(service, loggerFactory); var client = new TaskHubClient(service, loggerFactory: loggerFactory); // ... ``` -------------------------------- ### Console Application Setup with Application Insights Source: https://github.com/azure/durabletask/blob/main/docs/telemetry/application-insights.md Set up Application Insights and Durable Task Framework components for a console application, including logger factory and task hub worker. ```csharp using Microsoft.ApplicationInsights; using Microsoft.ApplicationInsights.Extensibility; using Microsoft.Azure.DurableTask.ApplicationInsights; using DurableTask.Core; using DurableTask.Emulator; // Configure Application Insights var configuration = TelemetryConfiguration.CreateDefault(); configuration.ConnectionString = "InstrumentationKey=..."; // Add the DurableTask telemetry module var module = new DurableTelemetryModule(); module.Initialize(configuration); var telemetryClient = new TelemetryClient(configuration); // Create logger factory for diagnostics using ILoggerFactory loggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); builder.SetMinimumLevel(LogLevel.Information); }); // Create DTFx components var service = new LocalOrchestrationService(); var worker = new TaskHubWorker(service, loggerFactory); worker.AddTaskOrchestrations(typeof(MyOrchestration)); worker.AddTaskActivities(typeof(MyActivity)); await worker.StartAsync(); // ... run orchestrations ... await worker.StopAsync(); // Ensure telemetry is flushed telemetryClient.Flush(); await Task.Delay(TimeSpan.FromSeconds(5)); ``` -------------------------------- ### Event History Representation Source: https://github.com/azure/durabletask/blob/main/docs/features/external-events.md Example of how an external event is recorded in the orchestration history. ```text EventRaised { Name: "Approval", Input: "{...}" } ``` -------------------------------- ### Register Orchestrations with Worker Source: https://github.com/azure/durabletask/blob/main/docs/concepts/orchestrations.md Register orchestration types with the TaskHubWorker before starting the worker instance. ```csharp var worker = new TaskHubWorker(service, loggerFactory); worker.AddTaskOrchestrations(typeof(OrderProcessingOrchestration)); await worker.StartAsync(); ``` -------------------------------- ### Invoke Sub-Orchestrations Source: https://github.com/azure/durabletask/blob/main/docs/concepts/orchestrations.md Start sub-orchestrations using CreateSubOrchestrationInstance, optionally specifying a custom instance ID. ```csharp // Start a sub-orchestration var subResult = await context.CreateSubOrchestrationInstance( typeof(SubOrchestration), subInput); // With custom instance ID var subResult = await context.CreateSubOrchestrationInstance( typeof(SubOrchestration), "sub-instance-123", subInput); ``` -------------------------------- ### IOrchestrationServiceClient Interface Source: https://github.com/azure/durabletask/blob/main/docs/providers/custom-provider.md Interface for client operations, including starting, querying, and managing orchestration instances. ```APIDOC ## IOrchestrationServiceClient ### Description For client operations (starting, querying, managing instances). ### Methods - `Task CreateTaskOrchestrationAsync(TaskMessage creationMessage)` - `Task CreateTaskOrchestrationAsync(TaskMessage creationMessage, OrchestrationStatus[] dedupeStatuses)` - `Task SendTaskOrchestrationMessageAsync(TaskMessage message)` - `Task SendTaskOrchestrationMessageBatchAsync(params TaskMessage[] messages)` - `Task WaitForOrchestrationAsync(string instanceId, string executionId, TimeSpan timeout, CancellationToken cancellationToken)` - `Task ForceTerminateTaskOrchestrationAsync(string instanceId, string reason)` - `Task GetOrchestrationStateAsync(string instanceId, string executionId)` - `Task> GetOrchestrationStateAsync(string instanceId, bool allExecutions)` - `Task GetOrchestrationHistoryAsync(string instanceId, string executionId)` - `Task PurgeOrchestrationHistoryAsync(DateTime thresholdDateTimeUtc, OrchestrationStateTimeRangeFilterType timeRangeFilterType)` ``` -------------------------------- ### Create and Query Orchestration Instance Source: https://github.com/azure/durabletask/wiki/Orchestration-Instance-Management Demonstrates how to create a new orchestration instance and then query its state using the TaskHubClient API. ```APIDOC ## Create and Query Orchestration Instance ### Description Creates a new orchestration instance and retrieves its initial state. ### Method `TaskHubClient.CreateOrchestrationInstance` and `TaskHubClient.GetOrchestrationState` ### Parameters #### CreateOrchestrationInstance - **orchestrationType** (Type) - Required - The type of the orchestration to create. - **input** (string) - Required - The input for the orchestration. #### GetOrchestrationState - **instance** (OrchestrationInstance) - Required - The instance information obtained from `CreateOrchestrationInstance`. ### Request Example ```csharp OrchestrationInstance instance = client.CreateOrchestrationInstance(typeof (EncodeVideoOrchestration), "http:///MyVideo.mpg"); OrchestrationState state = client.GetOrchestrationState(instance); Console.WriteLine(state.Name + " " + state.OrchestrationStatus + " " + state.Output); ``` ### Response #### Success Response (CreateOrchestrationInstance) - **OrchestrationInstance** - Information about the created orchestration instance. #### Success Response (GetOrchestrationState) - **OrchestrationState** - The current state of the orchestration instance, including its name, status, and output. ``` -------------------------------- ### Add Application Insights Integration Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/installation.md Install the optional Application Insights integration package for telemetry collection. ```bash dotnet add package Microsoft.Azure.DurableTask.ApplicationInsights ``` -------------------------------- ### Set Up Legacy Telemetry Callbacks Source: https://github.com/azure/durabletask/blob/main/docs/telemetry/distributed-tracing.md Manually set up CorrelationTraceClient with telemetry callbacks for request, dependency, and exception tracking. This is part of the legacy system and requires Application Insights. ```csharp using DurableTask.Core; using Microsoft.ApplicationInsights; // Set up telemetry callbacks CorrelationTraceClient.SetUp( (TraceContextBase requestTraceContext) => { requestTraceContext.Stop(); var requestTelemetry = requestTraceContext.CreateRequestTelemetry(); telemetryClient.TrackRequest(requestTelemetry); }, (TraceContextBase dependencyTraceContext) => { dependencyTraceContext.Stop(); var dependencyTelemetry = dependencyTraceContext.CreateDependencyTelemetry(); telemetryClient.TrackDependency(dependencyTelemetry); }, (Exception e) => { telemetryClient.TrackException(e); } ); ``` -------------------------------- ### Execute parallel tasks with Fan-Out/Fan-In in C# Source: https://github.com/azure/durabletask/blob/main/docs/concepts/orchestrations.md Starts multiple activities in parallel and waits for all to complete using Task.WhenAll. ```csharp public override async Task RunTask(OrchestrationContext context, int[] inputs) { // Fan-out: Start all tasks in parallel var tasks = inputs.Select(i => context.ScheduleTask(typeof(ProcessItemActivity), i)).ToList(); // Fan-in: Wait for all to complete var results = await Task.WhenAll(tasks); return results; } ``` -------------------------------- ### Continue As New Source: https://github.com/azure/durabletask/blob/main/docs/concepts/orchestrations.md Restart an orchestration with new input to implement eternal loops. ```csharp // Restart orchestration with new input (eternal orchestrations) context.ContinueAsNew(newInput); return default; // Return value is ignored ``` -------------------------------- ### Non-Deterministic Orchestration Exception Source: https://github.com/azure/durabletask/blob/main/docs/concepts/deterministic-constraints.md Example of the runtime error thrown when the orchestration replay history does not match the expected execution sequence. ```text NonDeterministicOrchestrationException: The orchestration 'MyOrchestration' has a non-deterministic replay detected. The history expected 'TaskScheduled' for 'ActivityA' but got 'TaskScheduled' for 'ActivityB'. ``` -------------------------------- ### Task Hub Management with TaskHubWorker Source: https://github.com/azure/durabletask/wiki/Task-Hub-Management Demonstrates how to initialize and use TaskHubWorker to create, check existence, and delete a task hub. The Azure Storage connection string is optional; omitting it means instance data won't be available for querying. ```csharp string serviceBusConnString = "Endpoint=sb://.servicebus.windows.net/;SharedSecretIssuer=[issuer];SharedSecretValue=[value]"; string tableConnectionString = "UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://127.0.0.1:10002/"; TaskHubWorker hubWorker = new TaskHubWorker("mytesthub", serviceBusConnString, tableConnectionString); // creates the required underlying entities in Service Bus and Azure Storage for the task hub hubWorker.CreateHub(); // creates the required underlying entities in Service Bus and Azure Storage for the task hub // only if they don't already exist hubWorker.CreateHubIfNotExists(); // deletes the underlying entities in Service Bus and Azure Storage for the task hub hubWorker.DeleteHub(); // existence check bool hubExists = hubWorker.HubExists(); ``` -------------------------------- ### Create Sub-Orchestration with Auto-Generated ID Source: https://github.com/azure/durabletask/blob/main/docs/features/sub-orchestrations.md Use this when you don't need a specific ID for the sub-orchestration and prefer an automatically generated GUID. ```csharp // ID is an automatically generated GUID var result = await context.CreateSubOrchestrationInstance( typeof(ChildOrchestration), input); ``` -------------------------------- ### Build the Solution Source: https://github.com/azure/durabletask/blob/main/test/AzureServiceFabricTests.md Builds the Durable Task solution using .NET CLI. Ensure the platform is set to x64 for compatibility. ```powershell dotnet build DurableTask.sln -c Debug -p:Platform=x64 ``` -------------------------------- ### Get Sub-Orchestration Status from Activity or External Code Source: https://github.com/azure/durabletask/blob/main/docs/features/sub-orchestrations.md Retrieve the status of a sub-orchestration using `TaskHubClient.GetOrchestrationStateAsync` from an activity or any external code. ```csharp // From an activity or external code var service = GetOrchestrationService(); var client = new TaskHubClient(service, loggerFactory: loggerFactory); var state = await client.GetOrchestrationStateAsync( new OrchestrationInstance { InstanceId = subOrchestrationId }); ``` -------------------------------- ### Worker Initialization Source: https://github.com/azure/durabletask/blob/main/docs/providers/azure-storage.md Demonstrates how multiple workers can connect to the same task hub using the Azure Storage provider. ```APIDOC ## Worker Initialization Multiple workers can connect to the same task hub: ```csharp // Worker 1, 2, 3... all connect to same task hub var service = new AzureStorageOrchestrationService(settings); var worker = new TaskHubWorker(service, loggerFactory); await worker.StartAsync(); ``` Partitions are automatically distributed across workers. ``` -------------------------------- ### Service Fabric Partitioning Configuration Source: https://github.com/azure/durabletask/blob/main/docs/providers/service-fabric.md Defines the partitioning strategy for a Service Fabric stateful service. This example uses uniform int64 partitioning. ```xml ``` -------------------------------- ### Implement the orchestration host Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/quickstart.md Configure the TaskHubWorker and TaskHubClient in Program.cs to execute the orchestration. ```csharp using DurableTask.Core; using DurableTask.Emulator; using Microsoft.Extensions.Logging; // Create logger factory for diagnostics using ILoggerFactory loggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); builder.SetMinimumLevel(LogLevel.Information); }); // Create the in-memory orchestration service var service = new LocalOrchestrationService(); // Create and configure the worker var worker = new TaskHubWorker(service, loggerFactory); worker.AddTaskOrchestrations(typeof(GreetingOrchestration)); worker.AddTaskActivities(typeof(GreetActivity)); // Start the worker await worker.StartAsync(); Console.WriteLine("Worker started."); // Create a client to start orchestrations var client = new TaskHubClient(service, loggerFactory: loggerFactory); // Start a new orchestration instance var instance = await client.CreateOrchestrationInstanceAsync( typeof(GreetingOrchestration), "World"); Console.WriteLine($"Started orchestration: {instance.InstanceId}"); // Wait for completion var result = await client.WaitForOrchestrationAsync( instance, TimeSpan.FromSeconds(30)); Console.WriteLine($"Result: {result.Output}"); Console.WriteLine($"Status: {result.OrchestrationStatus}"); // Stop the worker await worker.StopAsync(); ``` -------------------------------- ### Configure Tracer Provider for OpenTelemetry Source: https://github.com/azure/durabletask/blob/main/samples/DistributedTraceSample/OpenTelemetry/README.md Add this startup code to create a tracer provider, specifying the service name, trace source, and telemetry exporters. Ensure the `AZURE_MONITOR_CONNECTION_STRING` environment variable is set for Application Insights. ```csharp using var tracerProvider = Sdk.CreateTracerProviderBuilder() .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MySample")) .AddSource("DurableTask.Core") .AddConsoleExporter() .AddZipkinExporter() .AddAzureMonitorTraceExporter(options => { options.ConnectionString = Environment.GetEnvironmentVariable("AZURE_MONITOR_CONNECTION_STRING"); }) .Build(); ``` -------------------------------- ### Add Migration Point in Orchestration Source: https://github.com/azure/durabletask/blob/main/docs/features/versioning.md Check if a migration is needed and start a V2 orchestration with the current state if so. Otherwise, continue with V1 logic. ```csharp // V1: Add migration check public override async Task RunTask(OrchestrationContext context, Input input) { // Check if migration is needed if (input.ShouldMigrate) { // Start V2 orchestration with current state var result = await context.CreateSubOrchestrationInstance( "OrderOrchestration", "2.0", input); return result; } // Continue with V1 logic var a = await context.ScheduleTask(typeof(ActivityA), input); return new Result { Data = a }; } ``` -------------------------------- ### Configuring Partition Count Source: https://github.com/azure/durabletask/blob/main/docs/providers/azure-storage.md Shows how to increase the partition count for high-throughput scenarios. ```APIDOC ## Configuring Partition Count For high-throughput scenarios, increase partition count: ```csharp var settings = new AzureStorageOrchestrationServiceSettings { PartitionCount = 16 // More partitions = more parallelism }; ``` > [!WARNING] > Partition count cannot be changed after task hub creation. ``` -------------------------------- ### Create Task Hub Source: https://github.com/azure/durabletask/blob/main/docs/providers/azure-storage.md Asynchronously creates the task hub if it does not already exist. ```APIDOC ## Create Task Hub ```csharp await service.CreateIfNotExistsAsync(); ``` ``` -------------------------------- ### Schema Evolution for Versioned Data Source: https://github.com/azure/durabletask/blob/main/docs/advanced/serialization.md Demonstrates how to handle schema evolution by versioning data classes. Use default values for new properties to ensure backward compatibility with older data. ```csharp // Version 1 public class OrderV1 { public string OrderId { get; set; } public decimal Amount { get; set; } } // Version 2 - added property public class OrderV2 { public string OrderId { get; set; } public decimal Amount { get; set; } public string Currency { get; set; } = "USD"; // Default for old data } // Version 3 - renamed property public class OrderV3 { public string OrderId { get; set; } [JsonProperty("Amount")] // Map old name public decimal TotalAmount { get; set; } public string Currency { get; set; } = "USD"; } ``` -------------------------------- ### Minimal Custom Orchestration Service Implementation Source: https://github.com/azure/durabletask/blob/main/docs/providers/custom-provider.md This C# code provides a skeleton for a custom orchestration service provider, implementing the IOrchestrationService and IOrchestrationServiceClient interfaces. It includes basic implementations for lifecycle management, work item polling, and orchestration completion, relying on a hypothetical MyStorageBackend. ```csharp public class MyCustomOrchestrationService : IOrchestrationService, IOrchestrationServiceClient { private readonly MyStorageBackend _storage; public MyCustomOrchestrationService(string connectionString) { _storage = new MyStorageBackend(connectionString); } // Lifecycle public Task CreateAsync() => CreateIfNotExistsAsync(); public Task CreateAsync(bool recreateInstanceStore) => CreateIfNotExistsAsync(); public async Task CreateIfNotExistsAsync() { await _storage.InitializeAsync(); } public async Task DeleteAsync() { await _storage.DeleteAllDataAsync(); } public Task DeleteAsync(bool deleteInstanceStore) => DeleteAsync(); // Worker lifecycle public Task StartAsync() { // Start background processes if needed return Task.CompletedTask; } public Task StopAsync() => StopAsync(false); public Task StopAsync(bool isForced) { // Stop background processes return Task.CompletedTask; } // Work item polling public async Task LockNextTaskOrchestrationWorkItemAsync( TimeSpan receiveTimeout, CancellationToken cancellationToken) { // Poll for orchestration messages var message = await _storage.DequeueOrchestrationMessageAsync(receiveTimeout, cancellationToken); if (message == null) return null; // Load history var history = await _storage.LoadHistoryAsync(message.InstanceId); return new TaskOrchestrationWorkItem { InstanceId = message.InstanceId, NewMessages = new[] { message }, OrchestrationRuntimeState = new OrchestrationRuntimeState(history) }; } public async Task LockNextTaskActivityWorkItem( TimeSpan receiveTimeout, CancellationToken cancellationToken) { var message = await _storage.DequeueActivityMessageAsync(receiveTimeout, cancellationToken); if (message == null) return null; return new TaskActivityWorkItem { Id = Guid.NewGuid().ToString(), TaskMessage = message }; } // Orchestration completion public async Task CompleteTaskOrchestrationWorkItemAsync( TaskOrchestrationWorkItem workItem, OrchestrationRuntimeState newState, IList outboundMessages, IList orchestratorMessages, IList timerMessages, TaskMessage continuedAsNewMessage, OrchestrationState state) { // Save new history await _storage.SaveHistoryAsync(workItem.InstanceId, newState.Events); // Enqueue outbound messages (activities) foreach (var msg in outboundMessages) { await _storage.EnqueueActivityMessageAsync(msg); } // Enqueue orchestrator messages (sub-orchestrations, events) foreach (var msg in orchestratorMessages) { await _storage.EnqueueOrchestrationMessageAsync(msg); } // Handle timers foreach (var msg in timerMessages) { await _storage.ScheduleTimerAsync(msg); } // Handle continue-as-new if (continuedAsNewMessage != null) { await _storage.EnqueueOrchestrationMessageAsync(continuedAsNewMessage); } // Update instance status await _storage.UpdateInstanceStateAsync(workItem.InstanceId, state); } // ... implement remaining interface methods // Capabilities public int TaskOrchestrationDispatcherCount => 1; public int MaxConcurrentTaskOrchestrationWorkItems => settings.MaxOrchestrationConcurrency; public int TaskActivityDispatcherCount => 1; public int MaxConcurrentTaskActivityWorkItems => settings.MaxActivityConcurrency; public BehaviorOnContinueAsNew EventBehaviourForContinueAsNew => BehaviorOnContinueAsNew.Carryover; } ``` -------------------------------- ### Service Fabric Provider Settings Example Source: https://github.com/azure/durabletask/blob/main/docs/providers/service-fabric.md Configures settings for the Service Fabric orchestration and activity dispatchers. Adjust MaxConcurrent and DispatcherCount based on your workload. ```csharp var settings = new FabricOrchestrationProviderSettings { TaskOrchestrationDispatcherSettings = { MaxConcurrentOrchestrations = 500, DispatcherCount = 5 }, TaskActivityDispatcherSettings = { MaxConcurrentActivities = 500, DispatcherCount = 5 } }; ``` -------------------------------- ### Logging within Orchestrations with Replay Handling Source: https://github.com/azure/durabletask/blob/main/docs/telemetry/logging.md Demonstrates how to implement logging within an orchestration, ensuring logs are only written during actual execution and not during replay. It uses a static logger and checks `context.IsReplaying` before logging. ```csharp public class MyOrchestration : TaskOrchestration { // Use a static logger or configure via ObjectCreator private static readonly ILogger Logger = LoggerFactory .Create(builder => builder.AddConsole()) .CreateLogger(); public override async Task RunTask( OrchestrationContext context, string input) { // Only log during actual execution, not replay if (!context.IsReplaying) { Logger.LogInformation( "Processing orchestration {InstanceId} with input {Input}", context.OrchestrationInstance.InstanceId, input); } var result = await context.ScheduleTask(typeof(MyActivity), input); if (!context.IsReplaying) { Logger.LogInformation( "Orchestration {InstanceId} completed with result {Result}", context.OrchestrationInstance.InstanceId, result); } return result; } } ``` -------------------------------- ### Retry Specific Exceptions Source: https://github.com/azure/durabletask/blob/main/docs/features/retries.md Customize retry behavior by providing a `Handle` function that specifies which exceptions should trigger a retry. This example retries only on `HttpRequestException` or `TimeoutException`. ```csharp var options = new RetryOptions( firstRetryInterval: TimeSpan.FromSeconds(5), maxNumberOfAttempts: 3) { Handle = exception => { // Only retry on transient failures return exception is HttpRequestException || exception is TimeoutException; } }; ``` -------------------------------- ### Collect Orchestration Metrics Middleware Source: https://github.com/azure/durabletask/blob/main/docs/advanced/middleware.md Implement middleware to collect runtime metrics for orchestrations. This example records the duration and success/failure count of orchestration executions. ```csharp worker.AddOrchestrationDispatcherMiddleware(async (context, next) => { var runtimeState = context.GetProperty(); var orchestrationName = runtimeState?.Name ?? "unknown"; var stopwatch = Stopwatch.StartNew(); var success = true; try { await next(); } catch { success = false; throw; } finally { metrics.RecordDuration($"orchestration.{orchestrationName}.duration", stopwatch.Elapsed); metrics.RecordCounter(success ? "orchestration.success" : "orchestration.failure"); } }); ```