diff --git a/src/Abstractions/OrchestrationOptions.cs b/src/Abstractions/OrchestrationOptions.cs new file mode 100644 index 00000000..875760a1 --- /dev/null +++ b/src/Abstractions/OrchestrationOptions.cs @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.DurableTask; + +/// +/// Enum describing the runtime status of the orchestration. +/// +public enum OrchestrationRuntimeStatus +{ + /// + /// The orchestration started running. + /// + Running, + + /// + /// The orchestration completed normally. + /// + Completed, + + /// + /// The orchestration is transitioning into a new instance. + /// + [Obsolete("The ContinuedAsNew status is obsolete and exists only for compatibility reasons.")] + ContinuedAsNew, + + /// + /// The orchestration completed with an unhandled exception. + /// + Failed, + + /// + /// The orchestration canceled gracefully. + /// + [Obsolete("The Canceled status is not currently used and exists only for compatibility reasons.")] + Canceled, + + /// + /// The orchestration was abruptly terminated via a management API call. + /// + Terminated, + + /// + /// The orchestration was scheduled but hasn't started running. + /// + Pending, + + /// + /// The orchestration has been suspended. + /// + Suspended, +} diff --git a/src/Abstractions/TaskOptions.cs b/src/Abstractions/TaskOptions.cs index 63f94382..b0d3cef8 100644 --- a/src/Abstractions/TaskOptions.cs +++ b/src/Abstractions/TaskOptions.cs @@ -100,4 +100,7 @@ public SubOrchestrationOptions(TaskOptions options, string? instanceId = null) /// The time when the orchestration instance should start executing. If not specified or if a date-time in the past /// is specified, the orchestration instance will be scheduled immediately. /// -public record StartOrchestrationOptions(string? InstanceId = null, DateTimeOffset? StartAt = null); +/// The orchestration reuse policy. This allows for the reuse of an instance ID +/// if the instance ID referenced is in any of the states supplied in this parameter. +public record StartOrchestrationOptions(string? InstanceId = null, DateTimeOffset? StartAt = null, + OrchestrationRuntimeStatus[]? OrchestrationIdReusePolicy = null); diff --git a/src/Client/Grpc/GrpcDurableTaskClient.cs b/src/Client/Grpc/GrpcDurableTaskClient.cs index f0d6e6e8..ecef704a 100644 --- a/src/Client/Grpc/GrpcDurableTaskClient.cs +++ b/src/Client/Grpc/GrpcDurableTaskClient.cs @@ -83,6 +83,7 @@ public override async Task ScheduleNewOrchestrationInstanceAsync( Version = orchestratorName.Version, InstanceId = options?.InstanceId ?? Guid.NewGuid().ToString("N"), Input = this.DataConverter.Serialize(input), + OrchestrationIdReusePolicy = { }, }; DateTimeOffset? startAt = options?.StartAt; diff --git a/src/Client/OrchestrationServiceClientShim/Client.OrchestrationServiceClientShim.csproj b/src/Client/OrchestrationServiceClientShim/Client.OrchestrationServiceClientShim.csproj index b5389866..5a5be168 100644 --- a/src/Client/OrchestrationServiceClientShim/Client.OrchestrationServiceClientShim.csproj +++ b/src/Client/OrchestrationServiceClientShim/Client.OrchestrationServiceClientShim.csproj @@ -8,6 +8,11 @@ The client is responsible for interacting with orchestrations from outside the w true + + + + + 1.0.5 @@ -17,11 +22,13 @@ The client is responsible for interacting with orchestrations from outside the w + + diff --git a/src/Client/OrchestrationServiceClientShim/ShimDurableTaskClient.cs b/src/Client/OrchestrationServiceClientShim/ShimDurableTaskClient.cs index 3f3c5211..d31e8ee4 100644 --- a/src/Client/OrchestrationServiceClientShim/ShimDurableTaskClient.cs +++ b/src/Client/OrchestrationServiceClientShim/ShimDurableTaskClient.cs @@ -138,6 +138,18 @@ public override async Task ScheduleNewOrchestrationInstanceAsync( { cancellation.ThrowIfCancellationRequested(); string instanceId = options?.InstanceId ?? Guid.NewGuid().ToString("N"); + OrchestrationStatus[] runtimeStates = Array.Empty(); + + // Convert from DurableTask.OrchestrationRuntimeStatus to DurableTask.Core.OrchestrationRuntimeStatus + if (options?.OrchestrationIdReusePolicy != null) + { + runtimeStates = new OrchestrationStatus[options.OrchestrationIdReusePolicy.Length]; + for (int i = 0; i < options.OrchestrationIdReusePolicy.Length; i++) + { + runtimeStates[i] = ConvertState(options.OrchestrationIdReusePolicy[i]); + } + } + OrchestrationInstance instance = new() { InstanceId = instanceId, @@ -157,7 +169,7 @@ public override async Task ScheduleNewOrchestrationInstanceAsync( }, }; - await this.Client.CreateTaskOrchestrationAsync(message); + await this.Client.CreateTaskOrchestrationAsync(message, runtimeStates); return instanceId; } @@ -219,6 +231,28 @@ public override async Task WaitForInstanceStartAsync( } } + // Converts from DurableTask.OrchestrationRuntimeStatus to OrchestrationStatus for policy reuse. + static OrchestrationStatus ConvertState(DurableTask.OrchestrationRuntimeStatus state) + { + switch (state) + { + case DurableTask.OrchestrationRuntimeStatus.Running: + return OrchestrationStatus.Running; + case DurableTask.OrchestrationRuntimeStatus.Completed: + return OrchestrationStatus.Completed; + case DurableTask.OrchestrationRuntimeStatus.Failed: + return OrchestrationStatus.Failed; + case DurableTask.OrchestrationRuntimeStatus.Terminated: + return OrchestrationStatus.Terminated; + case DurableTask.OrchestrationRuntimeStatus.Pending: + return OrchestrationStatus.Pending; + case DurableTask.OrchestrationRuntimeStatus.Suspended: + return OrchestrationStatus.Suspended; + default: + return OrchestrationStatus.Terminated; + } + } + [return: NotNullIfNotNull("state")] OrchestrationMetadata? ToMetadata(Core.OrchestrationState? state, bool getInputsAndOutputs) {