Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
f222622
Add unversioned fallback for versioned task dispatch
torosent May 20, 2026
aab9708
Merge branch 'main' into unversioned-fallback
torosent May 20, 2026
24e9af4
Stabilize PerItem_HeartbeatReset_KeepsTimerAlive flaky test
torosent May 21, 2026
ad2e986
Clarify UnversionedFallbackMode doc comments
torosent May 21, 2026
91196c7
Merge branch 'main' into unversioned-fallback
torosent May 21, 2026
4c3b365
Clean up code-analysis warnings on touched files
torosent May 21, 2026
4ce5234
Drop redundant ASPNETCORE_URLS from DTS emulator docker command
torosent May 21, 2026
1809cdd
Split unversioned fallback into orchestrator + activity, rename, log …
torosent May 22, 2026
925b115
Address Copilot review nits on workitemfilters cref and timing comment
torosent May 22, 2026
077bd8d
Stop leaking worker dispatch contract into TaskOptions.Version doc
torosent May 22, 2026
887bc83
Document cross-environment version dispatch drift on TaskOptions.Version
torosent May 22, 2026
23e6bee
Correct OrchestratorUnversionedFallback strict-mode interaction note
torosent May 22, 2026
1c5ac73
Add UnversionedFallbackMode.StrictExactOnly; rename Never -> Implicit
torosent May 22, 2026
1b32e86
Update sample README key takeaways for the three-mode design
torosent May 22, 2026
8855022
Remove premature [Obsolete] Never alias
torosent May 22, 2026
457e5d6
Drop nullable annotation from XML doc cref signature
torosent May 26, 2026
baab660
Filter advertises strict worker version per name only when factory ca…
torosent May 26, 2026
62bee6c
Fix two Copilot review nits
torosent May 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Microsoft.DurableTask.sln
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ActivityVersioningSample",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityWithVersionedOrchestrationSample", "samples\EntityWithVersionedOrchestrationSample\EntityWithVersionedOrchestrationSample.csproj", "{8E0D27B3-2B5D-4B6F-A4E6-5C8E7B0F7DD2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnversionedFallbackSample", "samples\UnversionedFallbackSample\UnversionedFallbackSample.csproj", "{1C0E65CE-1B36-48BB-B688-FA3AAFDE8A25}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -761,6 +763,18 @@ Global
{8E0D27B3-2B5D-4B6F-A4E6-5C8E7B0F7DD2}.Release|x64.Build.0 = Release|Any CPU
{8E0D27B3-2B5D-4B6F-A4E6-5C8E7B0F7DD2}.Release|x86.ActiveCfg = Release|Any CPU
{8E0D27B3-2B5D-4B6F-A4E6-5C8E7B0F7DD2}.Release|x86.Build.0 = Release|Any CPU
{1C0E65CE-1B36-48BB-B688-FA3AAFDE8A25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1C0E65CE-1B36-48BB-B688-FA3AAFDE8A25}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1C0E65CE-1B36-48BB-B688-FA3AAFDE8A25}.Debug|x64.ActiveCfg = Debug|Any CPU
{1C0E65CE-1B36-48BB-B688-FA3AAFDE8A25}.Debug|x64.Build.0 = Debug|Any CPU
{1C0E65CE-1B36-48BB-B688-FA3AAFDE8A25}.Debug|x86.ActiveCfg = Debug|Any CPU
{1C0E65CE-1B36-48BB-B688-FA3AAFDE8A25}.Debug|x86.Build.0 = Debug|Any CPU
{1C0E65CE-1B36-48BB-B688-FA3AAFDE8A25}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1C0E65CE-1B36-48BB-B688-FA3AAFDE8A25}.Release|Any CPU.Build.0 = Release|Any CPU
{1C0E65CE-1B36-48BB-B688-FA3AAFDE8A25}.Release|x64.ActiveCfg = Release|Any CPU
{1C0E65CE-1B36-48BB-B688-FA3AAFDE8A25}.Release|x64.Build.0 = Release|Any CPU
{1C0E65CE-1B36-48BB-B688-FA3AAFDE8A25}.Release|x86.ActiveCfg = Release|Any CPU
{1C0E65CE-1B36-48BB-B688-FA3AAFDE8A25}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -824,6 +838,7 @@ Global
{1E30F09F-1ADA-4375-81CC-F0FBC74D5621} = {EFF7632B-821E-4CFC-B4A0-ED4B24296B17}
{3FBCFDBA-F547-4FD5-B8C6-0B645EF73E3A} = {EFF7632B-821E-4CFC-B4A0-ED4B24296B17}
{8E0D27B3-2B5D-4B6F-A4E6-5C8E7B0F7DD2} = {EFF7632B-821E-4CFC-B4A0-ED4B24296B17}
{1C0E65CE-1B36-48BB-B688-FA3AAFDE8A25} = {EFF7632B-821E-4CFC-B4A0-ED4B24296B17}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AB41CB55-35EA-4986-A522-387AB3402E71}
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ Durable Task Scheduler provides durable execution in Azure. Durable execution is

This SDK can also be used with the Durable Task Scheduler directly, without any Durable Functions dependency. For getting started, you can find documentation and samples [here](https://learn.microsoft.com/en-us/azure/azure-functions/durable/what-is-durable-task).

For runnable DTS emulator examples that demonstrate versioning, see the [WorkerVersioningSample](samples/WorkerVersioningSample/README.md) (deployment-based versioning), the [EternalOrchestrationVersionMigrationSample](samples/EternalOrchestrationVersionMigrationSample/README.md) (multi-version routing with `[DurableTask(Version = "...")]`), the [ActivityVersioningSample](samples/ActivityVersioningSample/README.md) (activity versioning with inherited defaults and explicit override support), and the [EntityWithVersionedOrchestrationSample](samples/EntityWithVersionedOrchestrationSample/README.md) (a single instance migrating v1→v2 via `ContinueAsNew(NewVersion)` while preserving entity-held state).
For runnable DTS emulator examples that demonstrate versioning, see the [WorkerVersioningSample](samples/WorkerVersioningSample/README.md) (deployment-based versioning), the [EternalOrchestrationVersionMigrationSample](samples/EternalOrchestrationVersionMigrationSample/README.md) (multi-version routing with `[DurableTask(Version = "...")]`), the [ActivityVersioningSample](samples/ActivityVersioningSample/README.md) (activity versioning with inherited defaults and explicit override support), the [EntityWithVersionedOrchestrationSample](samples/EntityWithVersionedOrchestrationSample/README.md) (a single instance migrating v1→v2 via `ContinueAsNew(NewVersion)` while preserving entity-held state), and the [UnversionedFallbackSample](samples/UnversionedFallbackSample/README.md) (an unversioned catch-all for unmatched explicit versions).

## Obtaining the Protobuf definitions

Expand Down
113 changes: 113 additions & 0 deletions samples/UnversionedFallbackSample/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

// This sample demonstrates opt-in unversioned fallback for per-task versioning.
// A worker can register one explicit legacy implementation for a known version
// and an unversioned implementation as the catch-all for versions that do not
// have an explicit [DurableTask(Version = "...")] registration.

using Microsoft.DurableTask;
using Microsoft.DurableTask.Client;
using Microsoft.DurableTask.Client.AzureManaged;
using Microsoft.DurableTask.Worker;
using Microsoft.DurableTask.Worker.AzureManaged;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

string connectionString = builder.Configuration.GetValue<string>("DURABLE_TASK_SCHEDULER_CONNECTION_STRING")
?? throw new InvalidOperationException(
"Set DURABLE_TASK_SCHEDULER_CONNECTION_STRING. " +
"For the local emulator: Endpoint=http://localhost:8080;TaskHub=default;Authentication=None");

builder.Services.AddDurableTaskWorker(wb =>
{
wb.AddTasks(tasks => tasks.AddAllGeneratedTasks());
wb.UseVersioning(new DurableTaskWorkerOptions.VersioningOptions
{
// This sample enables CatchAll fallback on both sides. Activity fallback is the safer place to
// start in your own code (activities are stateless and don't replay history); only enable
// orchestrator fallback when the unversioned orchestrator is replay-compatible with every
// version it may receive.
ActivityUnversionedFallback = DurableTaskWorkerOptions.UnversionedFallbackMode.CatchAll,
OrchestratorUnversionedFallback = DurableTaskWorkerOptions.UnversionedFallbackMode.CatchAll,
});
wb.UseWorkItemFilters();
wb.UseDurableTaskScheduler(connectionString);
});

builder.Services.AddDurableTaskClient(cb => cb.UseDurableTaskScheduler(connectionString));

IHost host = builder.Build();
await host.StartAsync();

await using DurableTaskClient client = host.Services.GetRequiredService<DurableTaskClient>();

Console.WriteLine("=== Unversioned fallback for versioned task dispatch ===");
Console.WriteLine();

SupportRequest request = new("Contoso", "BGP session down");

Console.WriteLine("Scheduling SupportWorkflow version 1.4.0 ...");
string legacyId = await client.ScheduleNewOrchestrationInstanceAsync(
nameof(SupportWorkflow),
request,
new StartOrchestrationOptions
{
Version = new TaskVersion("1.4.0"),
});
OrchestrationMetadata legacy = await client.WaitForInstanceCompletionAsync(legacyId, getInputsAndOutputs: true);
Console.WriteLine($" Result: {legacy.ReadOutputAs<string>()}");
Console.WriteLine();

Console.WriteLine("Scheduling SupportWorkflow version 1.0 ...");
string fallbackId = await client.ScheduleNewOrchestrationInstanceAsync(
nameof(SupportWorkflow),
request,
new StartOrchestrationOptions
{
Version = new TaskVersion("1.0"),
});
OrchestrationMetadata fallback = await client.WaitForInstanceCompletionAsync(fallbackId, getInputsAndOutputs: true);
Console.WriteLine($" Result: {fallback.ReadOutputAs<string>()}");
Console.WriteLine();

Console.WriteLine("Done! Version 1.4.0 used the explicit legacy class; version 1.0 used the unversioned fallback.");

await host.StopAsync();

/// <summary>
/// The current implementation. With OrchestratorUnversionedFallback enabled, this unversioned registration
/// handles every requested SupportWorkflow version that does not have an exact explicit registration.
/// </summary>
[DurableTask(nameof(SupportWorkflow))]
public sealed class SupportWorkflow : TaskOrchestrator<SupportRequest, string>
{
/// <inheritdoc />
public override Task<string> RunAsync(TaskOrchestrationContext context, SupportRequest input)
{
return Task.FromResult(
$"Current SupportWorkflow handled version '{context.Version}' for {input.Customer}: {input.Issue}");
}
}

/// <summary>
/// A pinned legacy implementation for version 1.4.0.
/// </summary>
[DurableTask(nameof(SupportWorkflow), Version = "1.4.0")]
public sealed class SupportWorkflowLegacyV140 : TaskOrchestrator<SupportRequest, string>
{
/// <inheritdoc />
public override Task<string> RunAsync(TaskOrchestrationContext context, SupportRequest input)
{
return Task.FromResult(
$"Legacy SupportWorkflow 1.4.0 handled version '{context.Version}' for {input.Customer}: {input.Issue}");
}
}

/// <summary>
/// Request input for the support workflow.
/// </summary>
public sealed record SupportRequest(string Customer, string Issue);
82 changes: 82 additions & 0 deletions samples/UnversionedFallbackSample/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Unversioned Fallback Sample

This sample demonstrates opt-in unversioned fallback for per-task versioning. It shows how one explicit versioned class can coexist with an unversioned catch-all implementation for versions that do not have their own `[DurableTask(Version = "...")]` registration.

## What it shows

- `SupportWorkflowLegacyV140` is registered as `[DurableTask(nameof(SupportWorkflow), Version = "1.4.0")]`.
- `SupportWorkflow` is registered without a version and acts as the current catch-all implementation.
- The worker enables both `OrchestratorUnversionedFallback = CatchAll` and `ActivityUnversionedFallback = CatchAll`. The orchestrator flag is what the demo exercises; the activity flag is set to illustrate that the two sides are configured independently.
- `UseWorkItemFilters()` is enabled, so the generated filter must allow unmatched versions to reach the worker.
- A version `1.4.0` request dispatches to the explicit legacy class.
- A version `1.0` request has no exact registration, so it dispatches to the unversioned fallback class.

## Prerequisites

- .NET 10.0 SDK
- [Docker](https://www.docker.com/get-started)

## Running the Sample

### 1. Start the DTS emulator

```bash
docker run --name durabletask-emulator -d -p 8080:8080 -p 8082:8082 mcr.microsoft.com/dts/dts-emulator:latest
```

The emulator exposes the gRPC sidecar on port 8080 and the local dashboard on port 8082. After running the sample below, you can open the dashboard at <http://localhost:8082> to inspect the orchestrations and their versions.

### 2. Set the connection string

```bash
export DURABLE_TASK_SCHEDULER_CONNECTION_STRING="Endpoint=http://localhost:8080;TaskHub=default;Authentication=None"
```

PowerShell:

```powershell
$env:DURABLE_TASK_SCHEDULER_CONNECTION_STRING = "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None"
```

### 3. Run the sample

```bash
dotnet run
```

Expected output:

```text
=== Unversioned fallback for versioned task dispatch ===

Scheduling SupportWorkflow version 1.4.0 ...
Result: Legacy SupportWorkflow 1.4.0 handled version '1.4.0' for Contoso: BGP session down

Scheduling SupportWorkflow version 1.0 ...
Result: Current SupportWorkflow handled version '1.0' for Contoso: BGP session down

Done! Version 1.4.0 used the explicit legacy class; version 1.0 used the unversioned fallback.
```

### 4. Clean up

```bash
docker rm -f durabletask-emulator
```

## Key takeaways

- Exact version matches always win. A `1.4.0` request dispatches to the `1.4.0` class, not the unversioned class.
- Three modes are available per side via `UnversionedFallbackMode`:
- `Implicit` (default) — the unversioned registration serves versioned requests only when the name has no versioned siblings. Matches behavior before per-task versioning shipped.
- `CatchAll` — opt-in catch-all for unmatched versioned requests on mixed names. This sample uses it.
- `StrictExactOnly` — every versioned request requires an exact `(name, version)` registration. Use when bogus versions from upstream clients should fail loudly.
- Orchestrator and activity fallback are configured independently. `OrchestratorUnversionedFallback` carries replay risk (orchestrators rehydrate state from history on every replay); `ActivityUnversionedFallback` is safer because activities are stateless. Start with activity-only `CatchAll` if you are unsure.
- Use orchestrator `CatchAll` only when the unversioned implementation is replay-compatible with the versions it may receive. Replaying existing histories against a different implementation can cause non-determinism or deserialization failures.
- `UseWorkItemFilters()` composes with these modes: it widens to a wildcard when the worker can actually serve unmatched versioned requests (under `Implicit` for unversioned-only names, under `CatchAll` whenever an unversioned registration exists). Under `StrictExactOnly` the filter emits the concrete version set so the backend does not deliver work items the worker would reject.

## See also

- [EternalOrchestrationVersionMigrationSample](../EternalOrchestrationVersionMigrationSample/README.md) — multi-version orchestration dispatch and `ContinueAsNew(NewVersion = "...")` migration.
- [ActivityVersioningSample](../ActivityVersioningSample/README.md) — activity versioning with inherited defaults and explicit overrides.
- [WorkerVersioningSample](../WorkerVersioningSample/README.md) — worker-level deployment versioning via `UseVersioning()`.
25 changes: 25 additions & 0 deletions samples/UnversionedFallbackSample/UnversionedFallbackSample.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>

<ItemGroup>
<!-- Using p2p references so we can show latest changes in samples. -->
<ProjectReference Include="$(SrcRoot)Client/AzureManaged/Client.AzureManaged.csproj" />
<ProjectReference Include="$(SrcRoot)Worker/AzureManaged/Worker.AzureManaged.csproj" />
<ProjectReference Include="$(SrcRoot)Analyzers/Analyzers.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />

<!-- Reference the source generator -->
<ProjectReference Include="$(SrcRoot)Generators/Generators.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>

</Project>
13 changes: 10 additions & 3 deletions src/Abstractions/TaskOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,16 @@ public TaskOptions(TaskOptions options)
/// </para>
/// <para>
/// When non-<c>null</c> (including <see cref="TaskVersion.Unversioned"/>), the task is scheduled with the
/// specified version explicitly. The worker dispatches to the registered <c>(name, version)</c> exactly;
/// when no exact match exists, it falls back to an unversioned registration only when the name has no
/// versioned registrations at all.
/// specified version explicitly, overriding any inherited version.
/// </para>
/// <para>
/// The receiving worker is responsible for resolving the scheduled version to a registered implementation
/// according to its own versioning configuration. That resolution is not visible to the scheduling client.
/// </para>
/// <para>
/// When deploying versioned workloads, treat each worker's versioning configuration as a deployment-time
/// policy: the same version value may dispatch to different registrations across deployments. Use the
/// worker's startup and per-dispatch diagnostic logs to verify behavior across environments.
/// </para>
/// </remarks>
public TaskVersion? Version { get; init; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.DurableTask.Worker.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace Microsoft.DurableTask.Worker;

Expand Down Expand Up @@ -54,10 +55,25 @@ public IHostedService Build(IServiceProvider serviceProvider)
Verify.NotNull(this.buildTarget, error);

DurableTaskRegistry registry = serviceProvider.GetOptions<DurableTaskRegistry>(this.Name);
DurableTaskWorkerOptions workerOptions = serviceProvider.GetOptions<DurableTaskWorkerOptions>(this.Name);
ILoggerFactory? loggerFactory = serviceProvider.GetService<ILoggerFactory>();
if (loggerFactory is not null && workerOptions.Versioning is { } versioning)
{
ILogger workerLogger = Logs.CreateWorkerLogger(loggerFactory);
if (versioning.OrchestratorUnversionedFallback == DurableTaskWorkerOptions.UnversionedFallbackMode.CatchAll)
{
workerLogger.OrchestratorUnversionedFallbackEnabled(this.Name);
}

if (versioning.ActivityUnversionedFallback == DurableTaskWorkerOptions.UnversionedFallbackMode.CatchAll)
{
workerLogger.ActivityUnversionedFallbackEnabled(this.Name);
}
}

// Note: Modifying any logic in this section could introduce breaking changes.
// Do not alter the input parameter.
return (IHostedService)ActivatorUtilities.CreateInstance(
serviceProvider, this.buildTarget, this.Name, registry.BuildFactory());
serviceProvider, this.buildTarget, this.Name, registry.BuildFactory(workerOptions, loggerFactory));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
where TTarget : DurableTaskWorker
where TOptions : DurableTaskWorkerOptions
{
builder.UseBuildTarget(typeof(TTarget));

Check warning on line 82 in src/Worker/Core/DependencyInjection/DurableTaskWorkerBuilderExtensions.cs

View workflow job for this annotation

GitHub Actions / smoke-tests

Prefer the generic overload 'Microsoft.DurableTask.Worker.DurableTaskWorkerBuilderExtensions.UseBuildTarget<TTarget>(Microsoft.DurableTask.Worker.IDurableTaskWorkerBuilder)' instead of 'Microsoft.DurableTask.Worker.DurableTaskWorkerBuilderExtensions.UseBuildTarget(Microsoft.DurableTask.Worker.IDurableTaskWorkerBuilder, System.Type)' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2263)

Check warning on line 82 in src/Worker/Core/DependencyInjection/DurableTaskWorkerBuilderExtensions.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Prefer the generic overload 'Microsoft.DurableTask.Worker.DurableTaskWorkerBuilderExtensions.UseBuildTarget<TTarget>(Microsoft.DurableTask.Worker.IDurableTaskWorkerBuilder)' instead of 'Microsoft.DurableTask.Worker.DurableTaskWorkerBuilderExtensions.UseBuildTarget(Microsoft.DurableTask.Worker.IDurableTaskWorkerBuilder, System.Type)' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2263)

Check warning on line 82 in src/Worker/Core/DependencyInjection/DurableTaskWorkerBuilderExtensions.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Prefer the generic overload 'Microsoft.DurableTask.Worker.DurableTaskWorkerBuilderExtensions.UseBuildTarget<TTarget>(Microsoft.DurableTask.Worker.IDurableTaskWorkerBuilder)' instead of 'Microsoft.DurableTask.Worker.DurableTaskWorkerBuilderExtensions.UseBuildTarget(Microsoft.DurableTask.Worker.IDurableTaskWorkerBuilder, System.Type)' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2263)

Check warning on line 82 in src/Worker/Core/DependencyInjection/DurableTaskWorkerBuilderExtensions.cs

View workflow job for this annotation

GitHub Actions / build

Prefer the generic overload 'Microsoft.DurableTask.Worker.DurableTaskWorkerBuilderExtensions.UseBuildTarget<TTarget>(Microsoft.DurableTask.Worker.IDurableTaskWorkerBuilder)' instead of 'Microsoft.DurableTask.Worker.DurableTaskWorkerBuilderExtensions.UseBuildTarget(Microsoft.DurableTask.Worker.IDurableTaskWorkerBuilder, System.Type)' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2263)
builder.Services.AddOptions<TOptions>(builder.Name)
.PostConfigure<IOptionsMonitor<DurableTaskWorkerOptions>>((options, baseOptions) =>
{
Expand All @@ -106,6 +106,8 @@
DefaultVersion = versionOptions.DefaultVersion,
MatchStrategy = versionOptions.MatchStrategy,
FailureStrategy = versionOptions.FailureStrategy,
OrchestratorUnversionedFallback = versionOptions.OrchestratorUnversionedFallback,
ActivityUnversionedFallback = versionOptions.ActivityUnversionedFallback,
};
});
return builder;
Expand Down Expand Up @@ -222,6 +224,15 @@
/// Only use this method when all task types referenced by orchestrations are guaranteed to be
/// registered with at least one connected worker.
/// </para>
/// <para>
/// Generated filters honor the worker's versioning configuration. Names that the worker cannot
/// serve under the current <see cref="DurableTaskWorkerOptions.VersioningOptions.MatchStrategy"/>
/// and <see cref="DurableTaskWorkerOptions.UnversionedFallbackMode"/> settings — for example, a
/// strict-versioned worker whose configured <see cref="DurableTaskWorkerOptions.VersioningOptions.Version"/>
/// has no exact registration and no enabled fallback path — are omitted from the generated filter
/// so the backend does not dispatch work items the worker would reject. If no connected worker
/// advertises a name, work items for that name remain undispatched until one does.
/// </para>
/// </remarks>
public static IDurableTaskWorkerBuilder UseWorkItemFilters(this IDurableTaskWorkerBuilder builder)
{
Expand Down
Loading
Loading