From ec03d94b26df62a2175287937fc1d53c5cc80e4b Mon Sep 17 00:00:00 2001 From: halspang Date: Mon, 21 Apr 2025 23:32:34 -0700 Subject: [PATCH 1/3] Add version to TaskName This commit adds an explict set for Version in TaskName. It also includes a flag that is set so other code can determine if the TaskName is intended to be versioned. Finally, it updates the Version property in the TaskOrchestrationContext as that was always set to empty instead of being able to be used. Signed-off-by: halspang --- CHANGELOG.md | 2 ++ src/Abstractions/TaskName.cs | 36 +++++++++++++++++++- src/Abstractions/TaskOrchestrationContext.cs | 4 +-- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index afc52e960..7fb8580d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ - Enrich User-Agent Header in gRPC Metadata to indicate Client or Worker as caller ([#421](https://github.com/microsoft/durabletask-dotnet/pull/421)) - Add extension methods for registering entities by type ([#427](https://github.com/microsoft/durabletask-dotnet/pull/427)) +>>>>>>> 766fa69 (Add version to TaskName) + ## v1.10.0 - Update DurableTask.Core to v3.1.0 and Bump version to v1.10.0 by @nytian in ([#411](https://github.com/microsoft/durabletask-dotnet/pull/411)) diff --git a/src/Abstractions/TaskName.cs b/src/Abstractions/TaskName.cs index 62d36f562..831af6aa4 100644 --- a/src/Abstractions/TaskName.cs +++ b/src/Abstractions/TaskName.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using System; + namespace Microsoft.DurableTask; /// @@ -25,7 +27,31 @@ public TaskName(string name) else { this.Name = name; - this.Version = string.Empty; // expose setting Version only when we actually consume it. + this.Version = string.Empty; + } + } + + /// + /// Initializes a new instance of the struct. + /// + /// + /// This TaskName is explicitly versioned, as compared to the default value. + /// + /// The name of the task. Providing null will yield the default struct, ignoring the version. + /// Optional. The version of the task. Providing null will yield the default value. + public TaskName(string name, string version) + { + if (name is null) + { + // Force the default struct when null is passed in. + this.Name = null!; + this.Version = null!; + } + else + { + this.IsVersioned = true; + this.Name = name; + this.Version = version == null ? null! : version; } } @@ -46,6 +72,14 @@ public TaskName(string name) /// public string Version { get; } + /// + /// Gets the flag denoting if this TaskName is versioned. + /// + /// + /// This flag is used to distinguish between the default (empty version) and a Task with an explicit empty version. + /// + public bool IsVersioned { get; } = false; + /// /// Implicitly converts a into a of the property value. /// diff --git a/src/Abstractions/TaskOrchestrationContext.cs b/src/Abstractions/TaskOrchestrationContext.cs index 95cc116ed..f050cfbea 100644 --- a/src/Abstractions/TaskOrchestrationContext.cs +++ b/src/Abstractions/TaskOrchestrationContext.cs @@ -61,9 +61,9 @@ public abstract class TaskOrchestrationContext public abstract bool IsReplaying { get; } /// - /// Gets the version of the current orchestration instance, which was set when the instance was created. + /// Gets or sets the version of the current orchestration instance, which was set when the instance was created. /// - public virtual string Version => string.Empty; + public virtual string Version { get; protected internal set; } = string.Empty; /// /// Gets the configuration settings for the orchestration context. From bb993ca6fff6850e8a71e67cf97f35a7390526b3 Mon Sep 17 00:00:00 2001 From: halspang Date: Thu, 15 May 2025 17:43:58 -0700 Subject: [PATCH 2/3] Move Version to TaskVersion and use as TaskOption Signed-off-by: halspang --- CHANGELOG.md | 3 +- src/Abstractions/TaskName.cs | 37 +----- src/Abstractions/TaskOptions.cs | 10 ++ src/Abstractions/TaskOrchestrationContext.cs | 4 +- src/Abstractions/TaskVersion.cs | 101 ++++++++++++++++ src/Client/Grpc/GrpcDurableTaskClient.cs | 5 +- .../DurableTaskWorkerBuilderExtensions.cs | 1 + src/Worker/Core/DurableTaskWorkerOptions.cs | 5 + .../Shims/TaskOrchestrationContextWrapper.cs | 12 +- .../OrchestrationPatterns.cs | 114 +++++++++++++++++- 10 files changed, 245 insertions(+), 47 deletions(-) create mode 100644 src/Abstractions/TaskVersion.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fb8580d3..ffc961a04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,7 @@ - Add user agent header to gRPC called in ([#417](https://github.com/microsoft/durabletask-dotnet/pull/417)) - Enrich User-Agent Header in gRPC Metadata to indicate Client or Worker as caller ([#421](https://github.com/microsoft/durabletask-dotnet/pull/421)) - Add extension methods for registering entities by type ([#427](https://github.com/microsoft/durabletask-dotnet/pull/427)) - ->>>>>>> 766fa69 (Add version to TaskName) +- Add TaskVersion and utilize it for version overrides when starting orchestrations ([#416](https://github.com/microsoft/durabletask-dotnet/pull/416)) ## v1.10.0 diff --git a/src/Abstractions/TaskName.cs b/src/Abstractions/TaskName.cs index 831af6aa4..62ab6b81d 100644 --- a/src/Abstractions/TaskName.cs +++ b/src/Abstractions/TaskName.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System; - namespace Microsoft.DurableTask; /// @@ -27,31 +25,7 @@ public TaskName(string name) else { this.Name = name; - this.Version = string.Empty; - } - } - - /// - /// Initializes a new instance of the struct. - /// - /// - /// This TaskName is explicitly versioned, as compared to the default value. - /// - /// The name of the task. Providing null will yield the default struct, ignoring the version. - /// Optional. The version of the task. Providing null will yield the default value. - public TaskName(string name, string version) - { - if (name is null) - { - // Force the default struct when null is passed in. - this.Name = null!; - this.Version = null!; - } - else - { - this.IsVersioned = true; - this.Name = name; - this.Version = version == null ? null! : version; + this.Version = string.Empty; // expose setting Version only when we actually consume it. } } @@ -70,16 +44,9 @@ public TaskName(string name, string version) /// Task versions is currently locked to as it is not yet integrated into task /// identification. This is being left here as we intend to support it soon. /// + [Obsolete("Refer to TaskVersion instead.")] public string Version { get; } - /// - /// Gets the flag denoting if this TaskName is versioned. - /// - /// - /// This flag is used to distinguish between the default (empty version) and a Task with an explicit empty version. - /// - public bool IsVersioned { get; } = false; - /// /// Implicitly converts a into a of the property value. /// diff --git a/src/Abstractions/TaskOptions.cs b/src/Abstractions/TaskOptions.cs index d3e06e5ca..6afd5f708 100644 --- a/src/Abstractions/TaskOptions.cs +++ b/src/Abstractions/TaskOptions.cs @@ -90,6 +90,11 @@ public SubOrchestrationOptions(TaskOptions options, string? instanceId = null) /// Gets the orchestration instance ID. /// public string? InstanceId { get; init; } + + /// + /// Gets the version to associate with the sub-orchestration instance. + /// + public TaskVersion Version { get; init; } = default!; } /// @@ -108,4 +113,9 @@ public record StartOrchestrationOptions(string? InstanceId = null, DateTimeOffse /// Gets the tags to associate with the orchestration instance. /// public IReadOnlyDictionary Tags { get; init; } = ImmutableDictionary.Create(); + + /// + /// Gets the version to associate with the orchestration instance. + /// + public TaskVersion? Version { get; init; } } diff --git a/src/Abstractions/TaskOrchestrationContext.cs b/src/Abstractions/TaskOrchestrationContext.cs index f050cfbea..95cc116ed 100644 --- a/src/Abstractions/TaskOrchestrationContext.cs +++ b/src/Abstractions/TaskOrchestrationContext.cs @@ -61,9 +61,9 @@ public abstract class TaskOrchestrationContext public abstract bool IsReplaying { get; } /// - /// Gets or sets the version of the current orchestration instance, which was set when the instance was created. + /// Gets the version of the current orchestration instance, which was set when the instance was created. /// - public virtual string Version { get; protected internal set; } = string.Empty; + public virtual string Version => string.Empty; /// /// Gets the configuration settings for the orchestration context. diff --git a/src/Abstractions/TaskVersion.cs b/src/Abstractions/TaskVersion.cs new file mode 100644 index 000000000..5d6d1bfec --- /dev/null +++ b/src/Abstractions/TaskVersion.cs @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.DurableTask; + +/// +/// The version of a durable task. +/// +public readonly struct TaskVersion : IEquatable +{ + /// + /// Initializes a new instance of the struct. + /// + /// The version of the task. Providing null will result in the default struct. + public TaskVersion(string version) + { + if (version == null) + { + this.Version = null!; + } + else + { + this.Version = version; + } + } + + /// + /// Gets the version of a task. + /// + public string Version { get; } + + /// + /// Implicitly converts a into a of the property value. + /// + /// The to be converted into a . + public static implicit operator string(TaskVersion value) => value.Version; + + /// + /// Implicitly converts a into a . + /// + /// The to convert into a . + public static implicit operator TaskVersion(string value) => new TaskVersion(value); + + /// + /// Compares two structs for equality. + /// + /// The first to compare. + /// The second to compare. + /// true if the two objects are equal; otherwise false. + public static bool operator ==(TaskVersion a, TaskVersion b) + { + return a.Equals(b); + } + + /// + /// Compares two structs for inequality. + /// + /// The first to compare. + /// The second to compare. + /// false if the two objects are equal; otherwise true. + public static bool operator !=(TaskVersion a, TaskVersion b) + { + return !a.Equals(b); + } + + /// + /// Gets a value indicating whether to objects + /// are equal using value semantics. + /// + /// The other to compare to. + /// true if the two are equal using value semantics; otherwise false. + public bool Equals(TaskVersion other) + { + return string.Equals(this.Version, other.Version, StringComparison.OrdinalIgnoreCase); + } + + /// + /// Gets a value indicating whether to objects + /// are equal using value semantics. + /// + /// The other object to compare to. + /// true if the two objects are equal using value semantics; otherwise false. + public override bool Equals(object? obj) + { + if (obj is not TaskVersion other) + { + return false; + } + + return this.Equals(other); + } + + /// + /// Calculates a hash code value for the current instance. + /// + /// A 32-bit hash code value. + public override int GetHashCode() + { + return StringComparer.OrdinalIgnoreCase.GetHashCode(this.Version); + } +} diff --git a/src/Client/Grpc/GrpcDurableTaskClient.cs b/src/Client/Grpc/GrpcDurableTaskClient.cs index a4960ae93..af9493228 100644 --- a/src/Client/Grpc/GrpcDurableTaskClient.cs +++ b/src/Client/Grpc/GrpcDurableTaskClient.cs @@ -78,10 +78,11 @@ public override async Task ScheduleNewOrchestrationInstanceAsync( { Check.NotEntity(this.options.EnableEntitySupport, options?.InstanceId); + // We're explicitly OK with an empty version from the options as that had to be explicitly set. It should take precedence over the default. string version = string.Empty; - if (!string.IsNullOrEmpty(orchestratorName.Version)) + if (options != null && options.Version != null) { - version = orchestratorName.Version; + version = options.Version; } else if (!string.IsNullOrEmpty(this.options.DefaultVersion)) { diff --git a/src/Worker/Core/DependencyInjection/DurableTaskWorkerBuilderExtensions.cs b/src/Worker/Core/DependencyInjection/DurableTaskWorkerBuilderExtensions.cs index 322e7d403..ee065f528 100644 --- a/src/Worker/Core/DependencyInjection/DurableTaskWorkerBuilderExtensions.cs +++ b/src/Worker/Core/DependencyInjection/DurableTaskWorkerBuilderExtensions.cs @@ -102,6 +102,7 @@ public static IDurableTaskWorkerBuilder UseVersioning(this IDurableTaskWorkerBui options.Versioning = new VersioningOptions { Version = versionOptions.Version, + DefaultVersion = versionOptions.DefaultVersion, MatchStrategy = versionOptions.MatchStrategy, FailureStrategy = versionOptions.FailureStrategy, }; diff --git a/src/Worker/Core/DurableTaskWorkerOptions.cs b/src/Worker/Core/DurableTaskWorkerOptions.cs index 395666c9a..b2bdca04b 100644 --- a/src/Worker/Core/DurableTaskWorkerOptions.cs +++ b/src/Worker/Core/DurableTaskWorkerOptions.cs @@ -203,6 +203,11 @@ public class VersioningOptions /// public string Version { get; set; } = string.Empty; + /// + /// Gets or sets the default version that will be used for starting new orchestrations. + /// + public string DefaultVersion { get; set; } = string.Empty; + /// /// Gets or sets the versioning strategy for the Durable Task worker. /// diff --git a/src/Worker/Core/Shims/TaskOrchestrationContextWrapper.cs b/src/Worker/Core/Shims/TaskOrchestrationContextWrapper.cs index a964020de..2d4c20409 100644 --- a/src/Worker/Core/Shims/TaskOrchestrationContextWrapper.cs +++ b/src/Worker/Core/Shims/TaskOrchestrationContextWrapper.cs @@ -177,10 +177,14 @@ public override async Task CallSubOrchestratorAsync( static string? GetInstanceId(TaskOptions? options) => options is SubOrchestrationOptions derived ? derived.InstanceId : null; string instanceId = GetInstanceId(options) ?? this.NewGuid().ToString("N"); + string defaultVersion = this.invocationContext.Options != null && this.invocationContext.Options.Versioning != null + ? this.invocationContext.Options.Versioning.DefaultVersion + : string.Empty; + string version = options != null && options is SubOrchestrationOptions subOptions ? subOptions.Version : defaultVersion; Check.NotEntity(this.invocationContext.Options.EnableEntitySupport, instanceId); - // if this orchestration uses entities, first validate that the suborchsestration call is allowed in the current context + // if this orchestration uses entities, first validate that the suborchestration call is allowed in the current context if (this.entityFeature != null && !this.entityFeature.EntityContext.ValidateSuborchestrationTransition(out string? errorMsg)) { throw new InvalidOperationException(errorMsg); @@ -192,7 +196,7 @@ public override async Task CallSubOrchestratorAsync( { return await this.innerContext.CreateSubOrchestrationInstanceWithRetry( orchestratorName.Name, - orchestratorName.Version, + version, instanceId, policy.ToDurableTaskCoreRetryOptions(), input); @@ -202,7 +206,7 @@ public override async Task CallSubOrchestratorAsync( return await this.InvokeWithCustomRetryHandler( () => this.innerContext.CreateSubOrchestrationInstance( orchestratorName.Name, - orchestratorName.Version, + version, instanceId, input), orchestratorName.Name, @@ -213,7 +217,7 @@ public override async Task CallSubOrchestratorAsync( { return await this.innerContext.CreateSubOrchestrationInstance( orchestratorName.Name, - orchestratorName.Version, + version, instanceId, input); } diff --git a/test/Grpc.IntegrationTests/OrchestrationPatterns.cs b/test/Grpc.IntegrationTests/OrchestrationPatterns.cs index 634427bc6..b64a5fa87 100644 --- a/test/Grpc.IntegrationTests/OrchestrationPatterns.cs +++ b/test/Grpc.IntegrationTests/OrchestrationPatterns.cs @@ -3,6 +3,7 @@ using System.Text.Json; using System.Text.Json.Nodes; +using Microsoft.DurableTask.Abstractions; using Microsoft.DurableTask.Client; using Microsoft.DurableTask.Tests.Logging; using Microsoft.DurableTask.Worker; @@ -213,7 +214,7 @@ public async Task SingleActivity() IReadOnlyCollection workerLogs = this.GetLogs("Microsoft.DurableTask.Worker"); Assert.NotEmpty(workerLogs); - + // Validate logs. Assert.Single(workerLogs, log => MatchLog( log, @@ -652,7 +653,6 @@ public async Task OrchestrationVersionPassedThroughContext() Assert.NotNull(output); Assert.Equal(output, $"Orchestration version: {version}"); - } [Fact] @@ -834,6 +834,116 @@ public async Task OrchestrationVersioning_MatchTypeCurrentOrOlder_VersionSuccess Assert.Equal(output, $"Orchestration version: {clientVersion}"); } + [Fact] + public async Task SubOrchestrationInheritsDefaultVersion() + { + var version = "0.1"; + await using HostTestLifetime server = await this.StartWorkerAsync(b => + { + b.AddTasks(tasks => tasks + .AddOrchestratorFunc("Versioned_Orchestration", (ctx, input) => + { + return ctx.CallSubOrchestratorAsync("Versioned_Sub_Orchestration"); + }) + .AddOrchestratorFunc("Versioned_Sub_Orchestration", (ctx, input) => + { + return ctx.CallActivityAsync("Versioned_Activity", ctx.Version); + }) + .AddActivityFunc("Versioned_Activity", (ctx, input) => + { + return $"Sub Orchestration version: {input}"; + })); + b.UseVersioning(new DurableTaskWorkerOptions.VersioningOptions + { + DefaultVersion = version + }); + }, c => + { + c.UseDefaultVersion(version); + }); + + var instanceId = await server.Client.ScheduleNewOrchestrationInstanceAsync("Versioned_Orchestration", input: string.Empty); + var result = await server.Client.WaitForInstanceCompletionAsync(instanceId, getInputsAndOutputs: true, this.TimeoutToken); + var output = result.ReadOutputAs(); + + Assert.NotNull(output); + Assert.Equal($"Sub Orchestration version: {version}", output); + } + + [Theory] + [InlineData("0.2")] + [InlineData("")] + public async Task OrchestrationTaskVersionOverridesDefaultVersion(string overrideVersion) + { + var version = "0.1"; + await using HostTestLifetime server = await this.StartWorkerAsync(b => + { + b.AddTasks(tasks => tasks + .AddOrchestratorFunc("Versioned_Orchestration", (ctx, input) => + { + return ctx.CallActivityAsync("Versioned_Activity", ctx.Version); + }) + .AddActivityFunc("Versioned_Activity", (ctx, input) => + { + return $"Orchestration version: {input}"; + })); + }, c => + { + c.UseDefaultVersion(version); + }); + + var instanceId = await server.Client.ScheduleNewOrchestrationInstanceAsync("Versioned_Orchestration", string.Empty, new StartOrchestrationOptions + { + Version = overrideVersion + }); + var result = await server.Client.WaitForInstanceCompletionAsync(instanceId, getInputsAndOutputs: true, this.TimeoutToken); + var output = result.ReadOutputAs(); + + Assert.NotNull(output); + Assert.Equal($"Orchestration version: {overrideVersion}", output); + } + + [Theory] + [InlineData("0.2")] + [InlineData("")] + public async Task SubOrchestrationTaskVersionOverridesDefaultVersion(string overrideVersion) + { + var version = "0.1"; + await using HostTestLifetime server = await this.StartWorkerAsync(b => + { + b.AddTasks(tasks => tasks + .AddOrchestratorFunc("Versioned_Orchestration", (ctx, input) => + { + return ctx.CallSubOrchestratorAsync("Versioned_Sub_Orchestration", new SubOrchestrationOptions + { + Version = overrideVersion + }); + }) + .AddOrchestratorFunc("Versioned_Sub_Orchestration", (ctx, input) => + { + return ctx.CallActivityAsync("Versioned_Activity", ctx.Version); + }) + .AddActivityFunc("Versioned_Activity", (ctx, input) => + { + return $"Sub Orchestration version: {input}"; + })); + b.UseVersioning(new DurableTaskWorkerOptions.VersioningOptions + { + DefaultVersion = version, + }); + }, c => + { + c.UseDefaultVersion(version); + }); + + var instanceId = await server.Client.ScheduleNewOrchestrationInstanceAsync("Versioned_Orchestration", input: string.Empty); + var result = await server.Client.WaitForInstanceCompletionAsync(instanceId, getInputsAndOutputs: true, this.TimeoutToken); + var output = result.ReadOutputAs(); + + Assert.NotNull(output); + Assert.Equal($"Sub Orchestration version: {overrideVersion}", output); + } + // TODO: Test for multiple external events with the same name // TODO: Test for ContinueAsNew with external events that carry over // TODO: Test for catching activity exceptions of specific types From a10d56401bf4182ce41e5cd9c42abf5e263c811c Mon Sep 17 00:00:00 2001 From: halspang Date: Wed, 21 May 2025 11:59:57 -0700 Subject: [PATCH 3/3] Update obsolete references and null operators Signed-off-by: halspang --- src/Abstractions/TaskName.cs | 4 ++++ src/Client/Grpc/GrpcDurableTaskClient.cs | 4 ++-- .../ShimDurableTaskClient.cs | 2 +- src/Worker/Core/Shims/TaskEntityShim.cs | 2 +- src/Worker/Core/Shims/TaskOrchestrationContextWrapper.cs | 8 ++++---- test/Abstractions.Tests/TaskNameTests.cs | 2 ++ .../ShimDurableTaskClientTests.cs | 2 +- 7 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/Abstractions/TaskName.cs b/src/Abstractions/TaskName.cs index 62ab6b81d..2ee9dcdf4 100644 --- a/src/Abstractions/TaskName.cs +++ b/src/Abstractions/TaskName.cs @@ -16,6 +16,7 @@ namespace Microsoft.DurableTask; /// The name of the task. Providing null will yield the default struct. public TaskName(string name) { +#pragma warning disable 0618 if (name is null) { // Force the default struct when null is passed in. @@ -27,6 +28,7 @@ public TaskName(string name) this.Name = name; this.Version = string.Empty; // expose setting Version only when we actually consume it. } +#pragma warning restore 0618 } /// @@ -123,6 +125,7 @@ public override int GetHashCode() /// The name and optional version of the current instance. public override string ToString() { +#pragma warning disable 0618 if (string.IsNullOrEmpty(this.Version)) { return this.Name; @@ -131,5 +134,6 @@ public override string ToString() { return this.Name + ":" + this.Version; } +#pragma warning restore 0618 } } diff --git a/src/Client/Grpc/GrpcDurableTaskClient.cs b/src/Client/Grpc/GrpcDurableTaskClient.cs index af9493228..6246435be 100644 --- a/src/Client/Grpc/GrpcDurableTaskClient.cs +++ b/src/Client/Grpc/GrpcDurableTaskClient.cs @@ -80,9 +80,9 @@ public override async Task ScheduleNewOrchestrationInstanceAsync( // We're explicitly OK with an empty version from the options as that had to be explicitly set. It should take precedence over the default. string version = string.Empty; - if (options != null && options.Version != null) + if (options?.Version is { } v) { - version = options.Version; + version = v; } else if (!string.IsNullOrEmpty(this.options.DefaultVersion)) { diff --git a/src/Client/OrchestrationServiceClientShim/ShimDurableTaskClient.cs b/src/Client/OrchestrationServiceClientShim/ShimDurableTaskClient.cs index fe7625a88..bcf8eb98a 100644 --- a/src/Client/OrchestrationServiceClientShim/ShimDurableTaskClient.cs +++ b/src/Client/OrchestrationServiceClientShim/ShimDurableTaskClient.cs @@ -172,7 +172,7 @@ public override async Task ScheduleNewOrchestrationInstanceAsync( Event = new ExecutionStartedEvent(-1, serializedInput) { Name = orchestratorName.Name, - Version = orchestratorName.Version, + Version = options?.Version ?? string.Empty, OrchestrationInstance = instance, ScheduledStartTime = options?.StartAt?.UtcDateTime, Tags = options?.Tags != null ? options.Tags.ToDictionary(kvp => kvp.Key, kvp => kvp.Value) : null, diff --git a/src/Worker/Core/Shims/TaskEntityShim.cs b/src/Worker/Core/Shims/TaskEntityShim.cs index 800b42bb6..8f47a88b2 100644 --- a/src/Worker/Core/Shims/TaskEntityShim.cs +++ b/src/Worker/Core/Shims/TaskEntityShim.cs @@ -221,7 +221,7 @@ public override string ScheduleNewOrchestration(TaskName name, object? input = n this.operationActions.Add(new StartNewOrchestrationOperationAction() { Name = name.Name, - Version = name.Version, + Version = options?.Version ?? string.Empty, InstanceId = instanceId, Input = this.dataConverter.Serialize(input), ScheduledStartTime = options?.StartAt?.UtcDateTime, diff --git a/src/Worker/Core/Shims/TaskOrchestrationContextWrapper.cs b/src/Worker/Core/Shims/TaskOrchestrationContextWrapper.cs index 2d4c20409..205ebb763 100644 --- a/src/Worker/Core/Shims/TaskOrchestrationContextWrapper.cs +++ b/src/Worker/Core/Shims/TaskOrchestrationContextWrapper.cs @@ -139,6 +139,7 @@ public override async Task CallActivityAsync( try { // TODO: Cancellation (https://github.com/microsoft/durabletask-dotnet/issues/7) +#pragma warning disable 0618 if (options?.Retry?.Policy is RetryPolicy policy) { return await this.innerContext.ScheduleWithRetry( @@ -165,6 +166,7 @@ public override async Task CallActivityAsync( // Hide the core DTFx types and instead use our own throw new TaskFailedException(name, e.ScheduleId, e); } +#pragma warning restore 0618 } /// @@ -177,10 +179,8 @@ public override async Task CallSubOrchestratorAsync( static string? GetInstanceId(TaskOptions? options) => options is SubOrchestrationOptions derived ? derived.InstanceId : null; string instanceId = GetInstanceId(options) ?? this.NewGuid().ToString("N"); - string defaultVersion = this.invocationContext.Options != null && this.invocationContext.Options.Versioning != null - ? this.invocationContext.Options.Versioning.DefaultVersion - : string.Empty; - string version = options != null && options is SubOrchestrationOptions subOptions ? subOptions.Version : defaultVersion; + string defaultVersion = this.invocationContext.Options?.Versioning?.DefaultVersion ?? string.Empty; + string version = options is SubOrchestrationOptions subOptions ? subOptions.Version : defaultVersion; Check.NotEntity(this.invocationContext.Options.EnableEntitySupport, instanceId); diff --git a/test/Abstractions.Tests/TaskNameTests.cs b/test/Abstractions.Tests/TaskNameTests.cs index b5cfc4350..fff8530d6 100644 --- a/test/Abstractions.Tests/TaskNameTests.cs +++ b/test/Abstractions.Tests/TaskNameTests.cs @@ -17,7 +17,9 @@ public void Ctor_EmptyName_Okay() { TaskName name = new(string.Empty); name.Name.Should().Be(string.Empty); +#pragma warning disable 0618 name.Version.Should().Be(string.Empty); +#pragma warning restore 0618 } [Theory] diff --git a/test/Client/OrchestrationServiceClientShim.Tests/ShimDurableTaskClientTests.cs b/test/Client/OrchestrationServiceClientShim.Tests/ShimDurableTaskClientTests.cs index a9a5d7caa..5eba17ede 100644 --- a/test/Client/OrchestrationServiceClientShim.Tests/ShimDurableTaskClientTests.cs +++ b/test/Client/OrchestrationServiceClientShim.Tests/ShimDurableTaskClientTests.cs @@ -400,7 +400,7 @@ static TaskMessage MatchStartExecutionMessage(TaskName name, object? input, Star } return Guid.TryParse(m.OrchestrationInstance.ExecutionId, out _) - && @event.Name == name.Name && @event.Version == name.Version + && @event.Name == name.Name && @event.Version == (options?.Version ?? string.Empty) && @event.OrchestrationInstance == m.OrchestrationInstance && @event.EventId == -1 && @event.Input == JsonDataConverter.Default.Serialize(input);