A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://docs.microsoft.com/azure/azure-functions/durable/durable-functions-orchestration-versioning below:

Orchestration versioning in Durable Functions - Azure

Orchestration versioning addresses the core challenge of deploying changes to orchestrator functions while maintaining the deterministic execution model that Durable Functions requires. Without this feature, breaking changes to orchestrator logic or activity function signatures would cause in-flight orchestration instances to fail during replay because they would break the determinism requirement that ensures reliable orchestration execution. This built-in feature provides automatic version isolation with minimal configuration. It's backend agnostic, so it can be used by apps leveraging any of the Durable Function's storage providers, including the Durable Task Scheduler.

Terminology

This article uses two related but distinct terms:

Understanding this distinction is crucial for orchestration versioning, where the orchestrator function code contains version-aware logic, while orchestration instances are permanently associated with a specific version when created.

How it works

The orchestration versioning feature operates on these core principles:

Important

Orchestration versioning is currently in public preview for apps running in the .NET isolated model. Use Microsoft.Azure.Functions.Worker.Extensions.DurableTask package version >=1.5.0.

Basic usage

The most common use case for orchestration versioning is when you need to make breaking changes to your orchestrator logic while keeping existing in-flight orchestration instances running with their original version. All you need to do is update the defaultVersion in your host.json and modify your orchestrator code to check the orchestration version and branch execution accordingly. Let's walk through the required steps.

Note

The behavior described in this section targets the most common situations, and this is what the default configuration provides. However, it can be modified if needed (see Advanced usage for details).

Step 1: defaultVersion configuration

To configure the default version for your orchestrations, you need to add or update the defaultVersion setting in the host.json file in your Azure Functions project:

{
  "extensions": {
    "durableTask": {
      "defaultVersion": "<version>"
    }
  }
}

The version string can follow any format that suits your versioning strategy:

After you set the defaultVersion, all new orchestration instances will be permanently associated with that version.

Version comparison rules

When the Strict or CurrentOrOlder strategy is selected (see Version matching), the runtime compares the orchestration instance's version with the defaultVersion value of the worker using the following rules:

Step 2: Orchestrator function logic

To implement version-aware logic in your orchestrator function, you can use the context parameter passed to the orchestrator to access the current orchestration instance's version, which allows you to branch your orchestrator logic based on the version.

Important

When implementing version-aware logic, it's critically important to preserve the exact orchestrator logic for older versions. Any changes to the sequence, order, or signature of activity calls for existing versions may break deterministic replay and cause in-flight orchestrations to fail or produce incorrect results. The old version code paths must remain unchanged once deployed.

[Function("MyOrchestrator")]
public static async Task<string> RunOrchestrator(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    if (context.Version == "1.0")
    {
        // Original logic for version 1.0
        ...
    }
    else if (context.Version == "2.0")
    {
        // New logic for version 2.0
        ...
    }
    ...
}

Note

The context.Version property is read-only and reflects the version that was permanently associated with the orchestration instance when it was created. You cannot modify this value during orchestration execution. If you want to specify a version through means other than host.json, you can do so when starting an orchestration instance with the orchestration client APIs (see Starting new orchestrations and sub-orchestrations with specific versions).

Tip

If you're just starting to use orchestration versioning and you already have in-flight orchestrations that were created before you specified a defaultVersion, you can still add the defaultVersion setting to your host.json now. For all previously created orchestrations, context.Version returns null (or an equivalent language-dependent value), so you can structure your orchestrator logic to handle both the legacy (null version) and new versioned orchestrations accordingly. In C#, you can check for context.Version == null or context.Version is null to handle the legacy case. Please also note that specifying "defaultVersion": null in host.json is equivalent to not specifying it at all.

Tip

Depending on your situation, you may prefer branching on different levels. You can make a local change precisely where this change is required, like the example shows. Alternatively, you can branch at a higher level, even at the entire orchestrator implementation level, which introduces some code duplication, but may keep the execution flow clear. It's up to you to choose the approach that best fits your scenario and coding style.

What happens after deployment

Here's what to expect once you deploy your updated orchestrator function with the new version logic:

Note

Orchestration versioning doesn't influence worker lifecycle. The Azure Functions platform manages worker provisioning and decommissioning based on regular rules depending on hosting options.

Example: Replacing an activity in the sequence

This example shows how to replace one activity with a different activity in the middle of a sequence using orchestration versioning.

Version 1.0

host.json configuration:

{
  "extensions": {
    "durableTask": {
      "defaultVersion": "1.0"
    }
  }
}

Orchestrator function:

[Function("ProcessOrderOrchestrator")]
public static async Task<string> ProcessOrder(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var orderId = context.GetInput<string>();
    
    await context.CallActivityAsync("ValidateOrder", orderId);
    await context.CallActivityAsync("ProcessPayment", orderId);
    await context.CallActivityAsync("ShipOrder", orderId);
    
    return "Order processed successfully";
}
Version 2.0 with discount processing

host.json configuration:

{
  "extensions": {
    "durableTask": {
      "defaultVersion": "2.0"
    }
  }
}

Orchestrator function:

using DurableTask.Core.Settings;

[Function("ProcessOrderOrchestrator")]
public static async Task<string> ProcessOrder(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var orderId = context.GetInput<string>();

    await context.CallActivityAsync("ValidateOrder", orderId);

    if (VersioningSettings.CompareVersions(context.Version, "1.0") <= 0)
    {
        // Preserve original logic for existing instances
        await context.CallActivityAsync("ProcessPayment", orderId);
    }
    else // a higher version (including 2.0)
    {
        // New logic with discount processing (replaces payment processing)
        await context.CallActivityAsync("ApplyDiscount", orderId);
        await context.CallActivityAsync("ProcessPaymentWithDiscount", orderId);
    }
    
    await context.CallActivityAsync("ShipOrder", orderId);

    return "Order processed successfully";
}
Advanced usage

For more sophisticated versioning scenarios, you can configure other settings to control how the runtime handles version matches and mismatches.

Tip

Use the default configuration (CurrentOrOlder with Reject) for most scenarios to enable safe rolling deployments while preserving orchestration state during version transitions. We recommend proceeding with the advanced configuration only if you have specific requirements that can't be met with the default behavior.

Version matching

The versionMatchStrategy setting determines how the runtime matches orchestration versions when loading orchestrator functions. It controls which orchestration instances a worker can process based on version compatibility.

Configuration
{
  "extensions": {
    "durableTask": {
      "defaultVersion": "<version>",
      "versionMatchStrategy": "CurrentOrOlder"
    }
  }
}
Available strategies Version mismatch handling

The versionFailureStrategy setting determines what happens when an orchestration instance version doesn't match the current defaultVersion.

Configuration:

{
  "extensions": {
    "durableTask": {
      "defaultVersion": "<version>",
      "versionFailureStrategy": "Reject"
    }
  }
}

Available strategies:

Starting new orchestrations and sub-orchestrations with specific versions

By default, all new orchestration instances are created with the current defaultVersion specified in your host.json configuration. However, you may have scenarios where you need to create orchestrations with a specific version, even if it differs from the current default.

When to use specific versions:

You can override the default version by providing a specific version value when creating new orchestration instances using the orchestration client APIs. This allows fine-grained control over which version each new orchestration instance uses.

[Function("HttpStart")]
public static async Task<HttpResponseData> HttpStart(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
    [DurableClient] DurableTaskClient client,
    FunctionContext executionContext)
{
    var options = new StartOrchestrationOptions
    {
        Version = "1.0"
    };
    
    string instanceId = await client.ScheduleNewOrchestrationInstanceAsync("ProcessOrderOrchestrator", orderId, options);

    // ...
}

You can also start sub-orchestrations with specific versions from within an orchestrator function:

[Function("MainOrchestrator")]
public static async Task<string> RunMainOrchestrator(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var subOptions = new SubOrchestratorOptions
    {
        Version = "1.0"
    };
    
    var result = await context.CallSubOrchestratorAsync<string>("ProcessPaymentOrchestrator", orderId, subOptions);
    
    // ...
}
Removing legacy code paths

Over time, you may want to remove legacy code paths from your orchestrator functions to simplify maintenance and reduce technical debt. However, removing code must be done carefully to avoid breaking existing orchestration instances.

When it's safe to remove legacy code:

Best practices for removal:

Warning

Removing legacy code paths while orchestration instances are still running those versions may cause deterministic replay failures or unexpected behavior. Always verify that no instances are using the legacy version before removing the code.

Best practices Version management Code organization Monitoring and observability Troubleshooting Common issues Next steps

Learn about zero-downtime deployment strategies

Learn about general versioning strategies


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4