### 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(); ``` -------------------------------- ### Start Orchestration Command Source: https://github.com/azure/durabletask/blob/main/samples/DurableTask.Samples/README.md Command to start a new orchestration instance. Specify the orchestration name and optionally provide parameters. ```bash DurableTask.Samples.exe -s [-p ] ``` -------------------------------- ### 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); ``` -------------------------------- ### 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 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 ``` -------------------------------- ### Install DTFx Packages Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/quickstart.md Add the necessary Durable Task Framework packages to your project, including the in-memory emulator for local development. ```bash dotnet add package Microsoft.Azure.DurableTask.Core 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 ``` -------------------------------- ### Run the Application Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/quickstart.md Execute the .NET application from the command line to start the DTFx worker and run the orchestration. ```bash dotnet run ``` -------------------------------- ### 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(); } } } ``` -------------------------------- ### 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); ``` -------------------------------- ### Start a Sub-Orchestration Instance Source: https://github.com/azure/durabletask/blob/main/docs/concepts/orchestrations.md Initiate a new sub-orchestration instance. Specify the result type, the sub-orchestration type, and its input. ```csharp // Start a sub-orchestration var subResult = await context.CreateSubOrchestrationInstance( typeof(SubOrchestration), subInput); ``` -------------------------------- ### 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 ``` -------------------------------- ### 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(); ``` -------------------------------- ### Start Sub-Orchestration with Custom Instance ID Source: https://github.com/azure/durabletask/blob/main/docs/concepts/orchestrations.md Start a sub-orchestration and assign it a specific instance ID. This is useful for predictable referencing of sub-orchestrations. ```csharp // With custom instance ID var subResult = await context.CreateSubOrchestrationInstance( typeof(SubOrchestration), "sub-instance-123", subInput); ``` -------------------------------- ### Start Orchestration from Client Code Source: https://github.com/azure/durabletask/blob/main/docs/concepts/orchestrations.md Initiate an orchestration from client code using `TaskHubClient.CreateOrchestrationInstanceAsync`. You can let the system generate an instance ID or provide a custom one. Scheduled orchestrations can also be started using `CreateScheduledOrchestrationInstanceAsync`. ```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)); ``` -------------------------------- ### 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); ``` -------------------------------- ### 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)); } ``` -------------------------------- ### Event History Example Source: https://github.com/azure/durabletask/blob/main/docs/features/external-events.md Illustrates how events are recorded in the orchestration history during replay. This format is used internally by the framework. ```text EventRaised { Name: "Approval", Input: "{...}" } ``` -------------------------------- ### 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 ``` -------------------------------- ### Define a Greeting Orchestration Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/quickstart.md Create an orchestration that coordinates the execution of activities. This example schedules the `GreetActivity` and returns its result. It inherits from `TaskOrchestration`. ```csharp using DurableTask.Core; public class GreetingOrchestration : TaskOrchestration { public override async Task RunTask(OrchestrationContext context, string input) { // Call the GreetActivity string greeting = await context.ScheduleTask(typeof(GreetActivity), input); return greeting; } } ``` -------------------------------- ### 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(); ``` -------------------------------- ### 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); ``` -------------------------------- ### 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(); }); ``` -------------------------------- ### 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 }; } ``` -------------------------------- ### 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); ``` -------------------------------- ### 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"); ``` -------------------------------- ### 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); ``` -------------------------------- ### 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) }; ``` -------------------------------- ### Avoid Using GUIDs Directly in Orchestrations Source: https://github.com/azure/durabletask/blob/main/docs/concepts/deterministic-constraints.md Use `context.NewGuid()` to generate GUIDs within an orchestration to ensure they are consistent across replays. Alternatively, generate the GUID in an activity. ```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); ``` -------------------------------- ### Best Practice: Immediate Restart with Work Source: https://github.com/azure/durabletask/blob/main/docs/features/eternal-orchestrations.md This code snippet shows an example of an immediate restart using ContinueAsNew when processing a batch of work, which is an acceptable pattern to minimize latency. ```csharp // ✅ OK - immediate restart when processing a batch of work if (pendingItems.Any()) { await ProcessBatchAsync(context, pendingItems); context.ContinueAsNew(state); // Restart immediately to check for more return null; } ``` -------------------------------- ### 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; } } ``` -------------------------------- ### Create New Console Project Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/quickstart.md Use the dotnet CLI to create a new console application and navigate into its directory. ```bash dotnet new console -n HelloDurableTask cd HelloDurableTask ``` -------------------------------- ### 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) ``` -------------------------------- ### 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(); ``` -------------------------------- ### Get Current Deterministic Time Source: https://github.com/azure/durabletask/blob/main/docs/concepts/orchestrations.md Use `context.CurrentUtcDateTime` to get the current time within an orchestration. This ensures deterministic behavior, unlike `DateTime.UtcNow` which can cause issues during replay. ```csharp // ✅ Correct - deterministic var now = context.CurrentUtcDateTime; // ❌ Wrong - non-deterministic var now = DateTime.UtcNow; ``` -------------------------------- ### 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)); ``` -------------------------------- ### 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 ``` -------------------------------- ### Configure and Run DTFx Host Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/quickstart.md Set up the `TaskHubWorker` and `TaskHubClient` to host and manage orchestrations. This includes configuring logging, creating the in-memory service, registering activities and orchestrations, and starting the worker. ```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(); ``` -------------------------------- ### 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)` ``` -------------------------------- ### 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 ``` -------------------------------- ### Greetings Orchestration Source: https://github.com/azure/durabletask/blob/main/samples/DurableTask.Samples/README.md A basic 'Hello World' orchestration that schedules two activities: GetUserTask and SendGreetingTask. ```csharp public class GreetingsOrchestration : TaskOrchestration { public override async Task RunTask(OrchestrationContext context, string input) { string greeting = await context.ScheduleTask(typeof(GetUserTask)); string result = await context.ScheduleTask(typeof(SendGreetingTask), greeting); return result; } } ``` -------------------------------- ### 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. ``` -------------------------------- ### Get Current Orchestration Instance ID Source: https://github.com/azure/durabletask/blob/main/docs/concepts/orchestrations.md Retrieve the unique identifier for the current orchestration instance using `context.OrchestrationInstance.InstanceId`. ```csharp string instanceId = context.OrchestrationInstance.InstanceId; ``` -------------------------------- ### 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); ``` -------------------------------- ### 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); } ); ``` -------------------------------- ### SumOfSquares Orchestration Source: https://github.com/azure/durabletask/blob/main/samples/DurableTask.Samples/README.md Another fan-out/fan-in example that computes the sum of squares from a JSON input file. Run with '-s SumOfSquares'. ```csharp public class SumOfSquaresOrchestration : TaskOrchestration { public override async Task RunTask(OrchestrationContext context, string input) { // This is a placeholder for the actual SumOfSquares orchestration logic. // The sample description indicates it computes sum of squares from a JSON input file. // It would likely involve deserializing the input, fanning out computations, // and fanning in the results. return 0; // Placeholder return value } } ``` -------------------------------- ### Greetings2 Orchestration Source: https://github.com/azure/durabletask/blob/main/samples/DurableTask.Samples/README.md Demonstrates parameterized orchestrations with a configurable number of greetings. Run with '-s Greetings2 -p 5'. ```csharp public class Greetings2Orchestration : TaskOrchestration { public override async Task RunTask(OrchestrationContext context, string input) { // This is a placeholder for the actual Greetings2 orchestration logic. // The sample description indicates it demonstrates parameterized orchestrations. // For example, it might loop 'input' number of times to send greetings. return "Greetings2 executed"; } } ``` -------------------------------- ### 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 }); ``` -------------------------------- ### 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(); ``` -------------------------------- ### 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 ``` -------------------------------- ### 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. ``` -------------------------------- ### TaskHubWorker and TaskHubClient Roles Source: https://github.com/azure/durabletask/blob/main/docs/getting-started/quickstart.md Explains the distinct roles of `TaskHubWorker` (hosting orchestrations and activities) and `TaskHubClient` (starting and managing orchestration instances). ```text - TaskHubWorker — Hosts orchestrations and activities - TaskHubClient — Starts and manages orchestration instances ``` -------------------------------- ### Schedule an Activity and Get Result Source: https://github.com/azure/durabletask/blob/main/docs/concepts/orchestrations.md Use context.ScheduleTask to invoke an activity function and wait for its result. Provide the activity type and input. ```csharp // Schedule an activity and wait for result var result = await context.ScheduleTask(typeof(MyActivity), input); ``` -------------------------------- ### 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 }; } ``` -------------------------------- ### 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(); ``` -------------------------------- ### 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 ``` -------------------------------- ### 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"; } ``` -------------------------------- ### Register Orchestrations with Task Hub Worker Source: https://github.com/azure/durabletask/blob/main/docs/concepts/orchestrations.md Register your custom orchestrations with the TaskHubWorker to make them available for execution. This is typically done during worker setup. ```csharp var worker = new TaskHubWorker(service, loggerFactory); worker.AddTaskOrchestrations(typeof(OrderProcessingOrchestration)); await worker.StartAsync(); ``` -------------------------------- ### 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; } ```