From c2a41d953902dd129b4afcdb5b55a173836ff6ad Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Tue, 3 Jan 2023 16:27:27 -0700 Subject: [PATCH 01/29] Initial work for workflows DotNET SDK Signed-off-by: Ryan Lettieri --- src/Dapr.Client/DaprClient.cs | 47 +++++++ src/Dapr.Client/DaprClientGrpc.cs | 112 ++++++++++++++++ src/Dapr.Client/GetWorkflowResponse.cs | 56 ++++++++ .../Protos/dapr/proto/dapr/v1/dapr.proto | 121 +++++++++++++++++- src/Dapr.Client/WorkflowReference.cs | 40 ++++++ test/Dapr.Client.Test/WorkflowApiTest.cs | 60 +++++++++ 6 files changed, 431 insertions(+), 5 deletions(-) create mode 100644 src/Dapr.Client/GetWorkflowResponse.cs create mode 100644 src/Dapr.Client/WorkflowReference.cs create mode 100644 test/Dapr.Client.Test/WorkflowApiTest.cs diff --git a/src/Dapr.Client/DaprClient.cs b/src/Dapr.Client/DaprClient.cs index 31d397545..8e4d7927a 100644 --- a/src/Dapr.Client/DaprClient.cs +++ b/src/Dapr.Client/DaprClient.cs @@ -941,6 +941,53 @@ public abstract Task Unlock( string lockOwner, CancellationToken cancellationToken = default); + /// + /// Attempt to start the given workflow with response indicating success. + /// + /// Identifier of the specific run. + /// The component to interface with. + /// Name of the workflow to run (function name). + /// The list of options that are potentially needed to start a workflow. + /// The input input for the given workflow. + /// A that can be used to cancel the operation. + /// A containing a + [Obsolete("This API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")] + public abstract Task StartWorkflow( + string instanceID, + string workflowComponent, + string workflowType, + Dictionary workflowOptions, + ByteString input, + CancellationToken cancellationToken = default); + + /// + /// Attempt to get information about the given workflow. + /// + /// Identifier of the specific run. + /// The component to interface with. + /// Name of the workflow to run (function name). + /// A that can be used to cancel the operation. + /// A containing a + [Obsolete("This API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")] + public abstract Task GetWorkflow( + string instanceID, + string workflowComponent, + string workflowType, + CancellationToken cancellationToken = default); + + /// + /// Attempt to get terminate the given workflow. + /// + /// Identifier of the specific run. + /// The component to interface with. + /// A that can be used to cancel the operation. + /// A that will complete when the operation has completed. If the wrapped value is true the operation suceeded. + [Obsolete("This API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")] + public abstract Task TerminateWorkflow( + string instanceID, + string workflowComponent, + CancellationToken cancellationToken = default); + /// public void Dispose() { diff --git a/src/Dapr.Client/DaprClientGrpc.cs b/src/Dapr.Client/DaprClientGrpc.cs index e292f0726..dd7b1916e 100644 --- a/src/Dapr.Client/DaprClientGrpc.cs +++ b/src/Dapr.Client/DaprClientGrpc.cs @@ -1374,6 +1374,118 @@ public async override Task Unlock( #endregion + + #region Workflow API + /// + [Obsolete] + public async override Task StartWorkflow( + string instanceId, + string workflowComponent, + string workflowType, + Dictionary workflowOptions, + ByteString input, + CancellationToken cancellationToken = default) + { + ArgumentVerifier.ThrowIfNullOrEmpty(instanceId, nameof(instanceId)); + ArgumentVerifier.ThrowIfNullOrEmpty(workflowComponent, nameof(workflowComponent)); + ArgumentVerifier.ThrowIfNullOrEmpty(workflowType, nameof(workflowType)); + ArgumentVerifier.ThrowIfNull(workflowOptions, nameof(workflowOptions)); + ArgumentVerifier.ThrowIfNull(input, nameof(input)); + + var request = new Autogenerated.StartWorkflowRequest() + { + InstanceId = instanceId, + WorkflowComponent = workflowComponent, + WorkflowName = workflowType, + Input = input + }; + + if (workflowOptions.Count > 0) + { + foreach (var item in workflowOptions) + { + request.Options[item.Key] = item.Value; + } + } + + try + { + var options = CreateCallOptions(headers: null, cancellationToken); + var response = await client.StartWorkflowAlpha1Async(request, options); + return new WorkflowReference(response.InstanceId); + + } + catch (RpcException ex) + { + throw new DaprException("Start Workflow operation failed: the Dapr endpoint indicated a failure. See InnerException for details.", ex); + } + } + + /// + [Obsolete] + public async override Task GetWorkflow( + string instanceId, + string workflowComponent, + string workflowType, + CancellationToken cancellationToken = default) + { + ArgumentVerifier.ThrowIfNullOrEmpty(instanceId, nameof(instanceId)); + ArgumentVerifier.ThrowIfNullOrEmpty(workflowComponent, nameof(workflowComponent)); + ArgumentVerifier.ThrowIfNullOrEmpty(workflowType, nameof(workflowType)); + + var request = new Autogenerated.GetWorkflowRequest() + { + InstanceId = instanceId, + WorkflowComponent = workflowComponent, + WorkflowType = workflowType + }; + + try + { + var options = CreateCallOptions(headers: null, cancellationToken); + var response = await client.GetWorkflowAlpha1Async(request, options); + return new GetWorkflowResponse(response.InstanceId, response.StartTime, response.Metadata); + } + catch (RpcException ex) + { + throw new DaprException("Get workflow operation failed: the Dapr endpoint indicated a failure. See InnerException for details.", ex); + } + + } + + + /// + [Obsolete] + public async override Task TerminateWorkflow( + string instanceID, + string workflowComponent, + CancellationToken cancellationToken = default) + { + ArgumentVerifier.ThrowIfNullOrEmpty(instanceID, nameof(instanceID)); + ArgumentVerifier.ThrowIfNullOrEmpty(workflowComponent, nameof(workflowComponent)); + + var request = new Autogenerated.TerminateWorkflowRequest() + { + InstanceId = instanceID, + WorkflowComponent = workflowComponent + }; + + var options = CreateCallOptions(headers: null, cancellationToken); + Autogenerated.TerminateWorkflowResponse response = new Autogenerated.TerminateWorkflowResponse(); // RRL Do we need a response? + try + { + response = await client.TerminateWorkflowAlpha1Async(request, options); + } + catch (RpcException ex) + { + throw new DaprException("Terminate workflow operation failed: the Dapr endpoint indicated a failure. See InnerException for details.", ex); + } + + } + + #endregion + + #region Dapr Sidecar Methods /// diff --git a/src/Dapr.Client/GetWorkflowResponse.cs b/src/Dapr.Client/GetWorkflowResponse.cs new file mode 100644 index 000000000..5504a951f --- /dev/null +++ b/src/Dapr.Client/GetWorkflowResponse.cs @@ -0,0 +1,56 @@ +// ------------------------------------------------------------------------ +// Copyright 2021 The Dapr Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; + +namespace Dapr.Client +{ + /// + /// Represents the response from invoking a binding. + /// + public sealed class GetWorkflowResponse + { + /// + /// Initializes a new .` + /// + /// The instance ID assocated with this response. + /// The time at which the workflow started executing. + /// The response metadata. + public GetWorkflowResponse(string instanceId, Int64 startTime, IReadOnlyDictionary metadata) + { + ArgumentVerifier.ThrowIfNull(instanceId, nameof(instanceId)); + ArgumentVerifier.ThrowIfNull(startTime, nameof(startTime)); + ArgumentVerifier.ThrowIfNull(metadata, nameof(metadata)); + + this.InstanceId = instanceId; + this.StartTime = startTime; + this.Metadata = metadata; + } + + /// + /// Gets the instance ID assocated with this response. + /// + public string InstanceId { set; get; } + + /// + /// Gets the time that the workflow started. + /// + public Int64 StartTime { set; get; } + + /// + /// Gets the response metadata. + /// + public IReadOnlyDictionary Metadata { set; get; } + } +} diff --git a/src/Dapr.Client/Protos/dapr/proto/dapr/v1/dapr.proto b/src/Dapr.Client/Protos/dapr/proto/dapr/v1/dapr.proto index b83256286..e464f91f9 100644 --- a/src/Dapr.Client/Protos/dapr/proto/dapr/v1/dapr.proto +++ b/src/Dapr.Client/Protos/dapr/proto/dapr/v1/dapr.proto @@ -17,6 +17,7 @@ package dapr.proto.runtime.v1; import "google/protobuf/any.proto"; import "google/protobuf/empty.proto"; +import "google/protobuf/timestamp.proto"; import "dapr/proto/common/v1/common.proto"; option csharp_namespace = "Dapr.Client.Autogen.Grpc.v1"; @@ -53,6 +54,9 @@ service Dapr { // Publishes events to the specific topic. rpc PublishEvent(PublishEventRequest) returns (google.protobuf.Empty) {} + // Bulk Publishes multiple events to the specified topic. + rpc BulkPublishEventAlpha1(BulkPublishRequest) returns (BulkPublishResponse) {} + // Invokes binding data to specific output bindings rpc InvokeBinding(InvokeBindingRequest) returns (InvokeBindingResponse) {} @@ -107,6 +111,15 @@ service Dapr { // Sets value in extended metadata of the sidecar rpc SetMetadata (SetMetadataRequest) returns (google.protobuf.Empty) {} + // Start Workflow + rpc StartWorkflowAlpha1 (StartWorkflowRequest) returns (WorkflowReference) {} + + // Get Workflow details + rpc GetWorkflowAlpha1 (GetWorkflowRequest) returns (GetWorkflowResponse) {} + + // Terminate Workflow + rpc TerminateWorkflowAlpha1 (TerminateWorkflowRequest) returns (TerminateWorkflowResponse) {} + // Shutdown the sidecar rpc Shutdown (google.protobuf.Empty) returns (google.protobuf.Empty) {} } @@ -287,6 +300,53 @@ message PublishEventRequest { map metadata = 5; } +// BulkPublishRequest is the message to bulk publish events to pubsub topic +message BulkPublishRequest { + // The name of the pubsub component + string pubsub_name = 1; + + // The pubsub topic + string topic = 2; + + // The entries which contain the individual events and associated details to be published + repeated BulkPublishRequestEntry entries = 3; + + // The request level metadata passing to to the pubsub components + map metadata = 4; +} + +// BulkPublishRequestEntry is the message containing the event to be bulk published +message BulkPublishRequestEntry { + // The request scoped unique ID referring to this message. Used to map status in response + string entry_id = 1; + + // The event which will be pulished to the topic + bytes event = 2; + + // The content type for the event + string content_type = 3; + + // The event level metadata passing to the pubsub component + map metadata = 4; +} + +// BulkPublishResponse is the message returned from a BulkPublishEvent call +message BulkPublishResponse { + // The entries for different events that failed publish in the BulkPublishEvent call + repeated BulkPublishResponseFailedEntry failedEntries = 1; +} + +// BulkPublishResponseFailedEntry is the message containing the entryID and error of a failed event in BulkPublishEvent call +message BulkPublishResponseFailedEntry { + + // The response scoped unique ID referring to this message + string entry_id = 1; + + // The error message if any on failure + string error = 3; +} + + // InvokeBindingRequest is the message to send data to output bindings message InvokeBindingRequest { // The name of the output binding to invoke. @@ -296,10 +356,10 @@ message InvokeBindingRequest { bytes data = 2; // The metadata passing to output binding components - // + // // Common metadata property: - // - ttlInSeconds : the time to live in seconds for the message. - // If set in the binding definition will cause all messages to + // - ttlInSeconds : the time to live in seconds for the message. + // If set in the binding definition will cause all messages to // have a default time to live. The message ttl overrides any value // in the binding definition. map metadata = 3; @@ -362,7 +422,7 @@ message TransactionalStateOperation { // The type of operation to be executed string operationType = 1; - // State values to be operated on + // State values to be operated on common.v1.StateItem request = 2; } @@ -455,6 +515,7 @@ message InvokeActorRequest { string actor_id = 2; string method = 3; bytes data = 4; + map metadata = 5; } // InvokeActorResponse is the method that returns an actor invocation response. @@ -468,6 +529,7 @@ message GetMetadataResponse { repeated ActiveActorsCount active_actors_count = 2; repeated RegisteredComponents registered_components = 3; map extended_metadata = 4; + repeated PubsubSubscription subscriptions = 5; } message ActiveActorsCount { @@ -482,6 +544,23 @@ message RegisteredComponents { repeated string capabilities = 4; } +message PubsubSubscription { + string pubsub_name = 1; + string topic = 2; + map metadata = 3; + PubsubSubscriptionRules rules = 4; + string dead_letter_topic = 5; +} + +message PubsubSubscriptionRules { + repeated PubsubSubscriptionRule rules = 1; +} + +message PubsubSubscriptionRule { + string match = 1; + string path = 2; +} + message SetMetadataRequest { string key = 1; string value = 2; @@ -595,4 +674,36 @@ message UnlockResponse { } Status status = 1; -} \ No newline at end of file +} + +message WorkflowReference { + string instance_id = 1; +} + +message GetWorkflowRequest { + string instance_id = 1; + string workflow_type = 2; + string workflow_component = 3; +} + +message GetWorkflowResponse { + string instance_id = 1; + int64 start_time = 2; + map metadata = 3; +} + +message StartWorkflowRequest { + string instance_id = 1; + string workflow_component = 2; + string workflow_name = 3; + map options = 4; + bytes input = 5; +} + +message TerminateWorkflowRequest { + string instance_id = 1; + string workflow_component = 2; +} + +message TerminateWorkflowResponse { +} diff --git a/src/Dapr.Client/WorkflowReference.cs b/src/Dapr.Client/WorkflowReference.cs new file mode 100644 index 000000000..2ae0b2c17 --- /dev/null +++ b/src/Dapr.Client/WorkflowReference.cs @@ -0,0 +1,40 @@ +// ------------------------------------------------------------------------ +// Copyright 2021 The Dapr Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; + +namespace Dapr.Client +{ + /// + /// Represents the response from invoking a workflow. + /// + public sealed class WorkflowReference + { + /// + /// Initializes a new .` + /// + /// The instance ID assocated with this response. + public WorkflowReference(string instanceId) + { + ArgumentVerifier.ThrowIfNull(instanceId, nameof(instanceId)); + this.InstanceId = instanceId; + } + + /// + /// Gets the instance ID assocated with this response. + /// + public string InstanceId { set; get; } + + } +} diff --git a/test/Dapr.Client.Test/WorkflowApiTest.cs b/test/Dapr.Client.Test/WorkflowApiTest.cs new file mode 100644 index 000000000..080724e1f --- /dev/null +++ b/test/Dapr.Client.Test/WorkflowApiTest.cs @@ -0,0 +1,60 @@ +// ------------------------------------------------------------------------ +// Copyright 2022 The Dapr Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +using System.Threading.Tasks; +using Autogenerated = Dapr.Client.Autogen.Grpc.v1; +using Xunit; +using FluentAssertions; +using System; +using System.Collections.Generic; +using Google.Protobuf.Reflection; +using Google.Protobuf; + +namespace Dapr.Client.Test +{ + + [System.Obsolete] + public class WorkflowApiTest + { + [Fact] + public async Task TryStartWorkflowAsync() + { + await using var client = TestClient.CreateForDaprClient(); + string instanceID = "testInstance"; + string workflowComponent = "testComponent"; + string workflowType = "testFunction"; + Dictionary workflowOptions = new Dictionary(); + ByteString input = ByteString.CopyFrom(0x01); + + workflowOptions.Add("task_queue", "testQueue"); + + var request = await client.CaptureGrpcRequestAsync(async daprClient => + { + return await daprClient.StartWorkflow(instanceID, workflowComponent, workflowType, workflowOptions, input); + }); + + // Get Request and validate + var envelope = await request.GetRequestEnvelopeAsync(); + envelope.InstanceId.Should().Be("testInstance"); + + // Get response and validate + var workflowResponse = new Autogenerated.GetWorkflowResponse{ + InstanceId = instanceID + }; + + var domainResponse = await request.CompleteWithMessageAsync(workflowResponse); + domainResponse.InstanceId.Should().Be("testInstance"); + } + + } +} \ No newline at end of file From 8cd0f0e7300b44ec945172fa29f2555f44454412 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Thu, 12 Jan 2023 16:04:57 -0700 Subject: [PATCH 02/29] Addressing review comments from authoring portion of workflow SDK Signed-off-by: Ryan Lettieri --- src/Dapr.Client/DaprClient.cs | 8 ++++---- src/Dapr.Client/DaprClientGrpc.cs | 14 +++++++------- src/Dapr.Client/GetWorkflowResponse.cs | 4 ++-- src/Dapr.Client/WorkflowReference.cs | 2 +- test/Dapr.Client.Test/WorkflowApiTest.cs | 8 ++++---- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Dapr.Client/DaprClient.cs b/src/Dapr.Client/DaprClient.cs index 8e4d7927a..7c4be1e26 100644 --- a/src/Dapr.Client/DaprClient.cs +++ b/src/Dapr.Client/DaprClient.cs @@ -946,7 +946,7 @@ public abstract Task Unlock( /// /// Identifier of the specific run. /// The component to interface with. - /// Name of the workflow to run (function name). + /// Name of the workflow to run. /// The list of options that are potentially needed to start a workflow. /// The input input for the given workflow. /// A that can be used to cancel the operation. @@ -956,8 +956,8 @@ public abstract Task StartWorkflow( string instanceID, string workflowComponent, string workflowType, - Dictionary workflowOptions, - ByteString input, + Object input, + IReadOnlyDictionary workflowOptions = default, CancellationToken cancellationToken = default); /// @@ -965,7 +965,7 @@ public abstract Task StartWorkflow( /// /// Identifier of the specific run. /// The component to interface with. - /// Name of the workflow to run (function name). + /// Name of the workflow to run. /// A that can be used to cancel the operation. /// A containing a [Obsolete("This API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")] diff --git a/src/Dapr.Client/DaprClientGrpc.cs b/src/Dapr.Client/DaprClientGrpc.cs index dd7b1916e..800bb9476 100644 --- a/src/Dapr.Client/DaprClientGrpc.cs +++ b/src/Dapr.Client/DaprClientGrpc.cs @@ -1382,8 +1382,8 @@ public async override Task StartWorkflow( string instanceId, string workflowComponent, string workflowType, - Dictionary workflowOptions, - ByteString input, + Object input, + IReadOnlyDictionary workflowOptions = default, CancellationToken cancellationToken = default) { ArgumentVerifier.ThrowIfNullOrEmpty(instanceId, nameof(instanceId)); @@ -1397,10 +1397,10 @@ public async override Task StartWorkflow( InstanceId = instanceId, WorkflowComponent = workflowComponent, WorkflowName = workflowType, - Input = input + Input = (ByteString)input }; - if (workflowOptions.Count > 0) + if (workflowOptions?.Count > 0) { foreach (var item in workflowOptions) { @@ -1442,9 +1442,9 @@ public async override Task GetWorkflow( try { - var options = CreateCallOptions(headers: null, cancellationToken); - var response = await client.GetWorkflowAlpha1Async(request, options); - return new GetWorkflowResponse(response.InstanceId, response.StartTime, response.Metadata); + var options = CreateCallOptions(headers: null, cancellationToken); + var response = await client.GetWorkflowAlpha1Async(request, options); + return new GetWorkflowResponse(response.InstanceId, response.StartTime, response.Metadata); } catch (RpcException ex) { diff --git a/src/Dapr.Client/GetWorkflowResponse.cs b/src/Dapr.Client/GetWorkflowResponse.cs index 5504a951f..bbacf819e 100644 --- a/src/Dapr.Client/GetWorkflowResponse.cs +++ b/src/Dapr.Client/GetWorkflowResponse.cs @@ -39,7 +39,7 @@ public GetWorkflowResponse(string instanceId, Int64 startTime, IReadOnlyDictiona } /// - /// Gets the instance ID assocated with this response. + /// Gets the workflow instance ID assocated with this response. /// public string InstanceId { set; get; } @@ -49,7 +49,7 @@ public GetWorkflowResponse(string instanceId, Int64 startTime, IReadOnlyDictiona public Int64 StartTime { set; get; } /// - /// Gets the response metadata. + /// Gets the response metadata from the associated workflow. This includes information such as start time and status of workflow. /// public IReadOnlyDictionary Metadata { set; get; } } diff --git a/src/Dapr.Client/WorkflowReference.cs b/src/Dapr.Client/WorkflowReference.cs index 2ae0b2c17..22489bb9d 100644 --- a/src/Dapr.Client/WorkflowReference.cs +++ b/src/Dapr.Client/WorkflowReference.cs @@ -32,7 +32,7 @@ public WorkflowReference(string instanceId) } /// - /// Gets the instance ID assocated with this response. + /// The instance ID assocated with this workflow. /// public string InstanceId { set; get; } diff --git a/test/Dapr.Client.Test/WorkflowApiTest.cs b/test/Dapr.Client.Test/WorkflowApiTest.cs index 080724e1f..a7221d4e5 100644 --- a/test/Dapr.Client.Test/WorkflowApiTest.cs +++ b/test/Dapr.Client.Test/WorkflowApiTest.cs @@ -33,19 +33,19 @@ public async Task TryStartWorkflowAsync() string instanceID = "testInstance"; string workflowComponent = "testComponent"; string workflowType = "testFunction"; + object input = ByteString.CopyFrom(0x01); Dictionary workflowOptions = new Dictionary(); - ByteString input = ByteString.CopyFrom(0x01); workflowOptions.Add("task_queue", "testQueue"); var request = await client.CaptureGrpcRequestAsync(async daprClient => { - return await daprClient.StartWorkflow(instanceID, workflowComponent, workflowType, workflowOptions, input); + return await daprClient.StartWorkflow(instanceID, workflowComponent, workflowType, input, workflowOptions); }); // Get Request and validate var envelope = await request.GetRequestEnvelopeAsync(); - envelope.InstanceId.Should().Be("testInstance"); + envelope.InstanceId.Should().Be("testInstance", "Instance ID was not correct"); // Get response and validate var workflowResponse = new Autogenerated.GetWorkflowResponse{ @@ -53,7 +53,7 @@ public async Task TryStartWorkflowAsync() }; var domainResponse = await request.CompleteWithMessageAsync(workflowResponse); - domainResponse.InstanceId.Should().Be("testInstance"); + domainResponse.InstanceId.Should().Be("testInstance", "Instance ID was not correct"); } } From 94cea4de8d495d8cbb951b5617092d75f04f8758 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Tue, 17 Jan 2023 15:39:22 -0700 Subject: [PATCH 03/29] Moving workflows test into E2E directory Signed-off-by: Ryan Lettieri --- test/Dapr.Client.Test/Dapr.Client.Test.csproj | 2 +- test/Dapr.Client.Test/WorkflowApiTest.cs | 60 ------------------ .../Dapr.E2E.Test.App.csproj | 1 + test/Dapr.E2E.Test.App/Startup.cs | 19 ++++++ test/Dapr.E2E.Test/Dapr.E2E.Test.csproj | 3 +- test/Dapr.E2E.Test/Workflows/WorkflowTest.cs | 61 +++++++++++++++++++ 6 files changed, 84 insertions(+), 62 deletions(-) delete mode 100644 test/Dapr.Client.Test/WorkflowApiTest.cs create mode 100644 test/Dapr.E2E.Test/Workflows/WorkflowTest.cs diff --git a/test/Dapr.Client.Test/Dapr.Client.Test.csproj b/test/Dapr.Client.Test/Dapr.Client.Test.csproj index d5e4fd183..d9a95bcb0 100644 --- a/test/Dapr.Client.Test/Dapr.Client.Test.csproj +++ b/test/Dapr.Client.Test/Dapr.Client.Test.csproj @@ -9,7 +9,7 @@ all - + diff --git a/test/Dapr.Client.Test/WorkflowApiTest.cs b/test/Dapr.Client.Test/WorkflowApiTest.cs deleted file mode 100644 index a7221d4e5..000000000 --- a/test/Dapr.Client.Test/WorkflowApiTest.cs +++ /dev/null @@ -1,60 +0,0 @@ -// ------------------------------------------------------------------------ -// Copyright 2022 The Dapr Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ------------------------------------------------------------------------ - -using System.Threading.Tasks; -using Autogenerated = Dapr.Client.Autogen.Grpc.v1; -using Xunit; -using FluentAssertions; -using System; -using System.Collections.Generic; -using Google.Protobuf.Reflection; -using Google.Protobuf; - -namespace Dapr.Client.Test -{ - - [System.Obsolete] - public class WorkflowApiTest - { - [Fact] - public async Task TryStartWorkflowAsync() - { - await using var client = TestClient.CreateForDaprClient(); - string instanceID = "testInstance"; - string workflowComponent = "testComponent"; - string workflowType = "testFunction"; - object input = ByteString.CopyFrom(0x01); - Dictionary workflowOptions = new Dictionary(); - - workflowOptions.Add("task_queue", "testQueue"); - - var request = await client.CaptureGrpcRequestAsync(async daprClient => - { - return await daprClient.StartWorkflow(instanceID, workflowComponent, workflowType, input, workflowOptions); - }); - - // Get Request and validate - var envelope = await request.GetRequestEnvelopeAsync(); - envelope.InstanceId.Should().Be("testInstance", "Instance ID was not correct"); - - // Get response and validate - var workflowResponse = new Autogenerated.GetWorkflowResponse{ - InstanceId = instanceID - }; - - var domainResponse = await request.CompleteWithMessageAsync(workflowResponse); - domainResponse.InstanceId.Should().Be("testInstance", "Instance ID was not correct"); - } - - } -} \ No newline at end of file diff --git a/test/Dapr.E2E.Test.App/Dapr.E2E.Test.App.csproj b/test/Dapr.E2E.Test.App/Dapr.E2E.Test.App.csproj index e1c1bc17c..2903f9516 100644 --- a/test/Dapr.E2E.Test.App/Dapr.E2E.Test.App.csproj +++ b/test/Dapr.E2E.Test.App/Dapr.E2E.Test.App.csproj @@ -8,5 +8,6 @@ + diff --git a/test/Dapr.E2E.Test.App/Startup.cs b/test/Dapr.E2E.Test.App/Startup.cs index d6c82413a..356a8d79d 100644 --- a/test/Dapr.E2E.Test.App/Startup.cs +++ b/test/Dapr.E2E.Test.App/Startup.cs @@ -25,6 +25,8 @@ namespace Dapr.E2E.Test using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; + using Dapr.Workflow; + using System.Threading.Tasks; /// /// Startup class. @@ -54,6 +56,23 @@ public void ConfigureServices(IServiceCollection services) services.AddAuthentication().AddDapr(); services.AddAuthorization(o => o.AddDapr()); services.AddControllers().AddDapr(); + // Register a workflow and associated activity + services.AddDaprWorkflow(options => + { + // Example of registering a "PlaceOrder" workflow function + options.RegisterWorkflow("PlaceOrder", implementation: async (context, input) => + { + // In real life there are other steps related to placing an order, like reserving + // inventory and charging the customer credit card etc. But let's keep it simple ;) + return await context.CallActivityAsync("ShipProduct", "Coffee Beans"); + }); + + // Example of registering a "ShipProduct" workflow activity function + options.RegisterActivity("ShipProduct", implementation: (context, input) => + { + return Task.FromResult($"We are shipping {input} to the customer using our hoard of drones!"); + }); + }); services.AddActors(options => { options.Actors.RegisterActor(); diff --git a/test/Dapr.E2E.Test/Dapr.E2E.Test.csproj b/test/Dapr.E2E.Test/Dapr.E2E.Test.csproj index 1edf1266c..170331999 100644 --- a/test/Dapr.E2E.Test/Dapr.E2E.Test.csproj +++ b/test/Dapr.E2E.Test/Dapr.E2E.Test.csproj @@ -4,7 +4,7 @@ - + @@ -16,6 +16,7 @@ + diff --git a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs new file mode 100644 index 000000000..e169ffb3d --- /dev/null +++ b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs @@ -0,0 +1,61 @@ +// ------------------------------------------------------------------------ +// Copyright 2022 The Dapr Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ------------------------------------------------------------------------ + +namespace Dapr.E2E.Test +{ + + using System.Threading; + using System.Threading.Tasks; + using Xunit; + using FluentAssertions; + using System; + using System.Collections.Generic; + using Google.Protobuf; + using Dapr.Client; + + [System.Obsolete] + public partial class E2ETests + { + [Fact] + public async Task TestWorkflows() + { + string instanceID = "testInstance"; + string workflowComponent = "testComponent"; + string workflowType = "PlaceOrder"; + object input = ByteString.CopyFrom(0x01); + Dictionary workflowOptions = new Dictionary(); + CancellationToken cts = new CancellationToken(); + + using var daprClient = new DaprClientBuilder().Build(); + + // Start the workflow + var startResponse = await daprClient.StartWorkflow(instanceID, workflowComponent, workflowType, input, null, cts); + + // Get Request and validate + startResponse.InstanceId.Should().Be("testInstance", "Instance ID was not correct"); + + // GET INFO TEST + var getResponse = await daprClient.GetWorkflow(instanceID, workflowComponent, workflowType); + getResponse.InstanceId.Should().Be("testInstance"); + getResponse.Metadata["status"].Should().Be("Running", "The workflow is not running when it is expected to be running"); + + + // TERMINATE TEST: + await daprClient.TerminateWorkflow(instanceID, workflowComponent); + getResponse = await daprClient.GetWorkflow(instanceID, workflowComponent, workflowType); + getResponse.Metadata["status"].Should().Be("Terminated", "The workflow is still running when it is expected to be terminated"); + + } + + } +} \ No newline at end of file From ba0d6b886ed0f516462648ef891d8fc74fe1bc40 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Tue, 17 Jan 2023 15:44:09 -0700 Subject: [PATCH 04/29] Adding back in workflow options Signed-off-by: Ryan Lettieri --- test/Dapr.E2E.Test/Workflows/WorkflowTest.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs index e169ffb3d..74ff50aee 100644 --- a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs +++ b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs @@ -34,12 +34,13 @@ public async Task TestWorkflows() string workflowType = "PlaceOrder"; object input = ByteString.CopyFrom(0x01); Dictionary workflowOptions = new Dictionary(); + workflowOptions.Add("task_queue", "testQueue"); CancellationToken cts = new CancellationToken(); using var daprClient = new DaprClientBuilder().Build(); // Start the workflow - var startResponse = await daprClient.StartWorkflow(instanceID, workflowComponent, workflowType, input, null, cts); + var startResponse = await daprClient.StartWorkflow(instanceID, workflowComponent, workflowType, input, workflowOptions, cts); // Get Request and validate startResponse.InstanceId.Should().Be("testInstance", "Instance ID was not correct"); From 9d2db440dac50f8802157329d2cc5c5c4719cdda Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Tue, 17 Jan 2023 16:02:28 -0700 Subject: [PATCH 05/29] Adding health check and updating itests for workflows Signed-off-by: Ryan Lettieri --- .github/workflows/itests.yml | 6 +++--- test/Dapr.E2E.Test/Workflows/WorkflowTest.cs | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/itests.yml b/.github/workflows/itests.yml index 7b8ac5b58..f1e20c598 100644 --- a/.github/workflows/itests.yml +++ b/.github/workflows/itests.yml @@ -45,11 +45,11 @@ jobs: GOOS: linux GOARCH: amd64 GOPROXY: https://proxy.golang.org - DAPR_CLI_VER: 1.8.0 - DAPR_RUNTIME_VER: 1.8.0 + DAPR_CLI_VER: 1.9.1 + DAPR_RUNTIME_VER: 1.9.5 DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/3dacfb672d55f1436c249057aaebbe597e1066f3/install/install.sh DAPR_CLI_REF: '' - DAPR_REF: '' + DAPR_REF: '06e7559eb58d09564d485835c7e8b21f20630794' steps: - name: Set up Dapr CLI run: wget -q ${{ env.DAPR_INSTALL_URL }} -O - | /bin/bash -s ${{ env.DAPR_CLI_VER }} diff --git a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs index 74ff50aee..48317f883 100644 --- a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs +++ b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs @@ -39,6 +39,9 @@ public async Task TestWorkflows() using var daprClient = new DaprClientBuilder().Build(); + var health = daprClient.CheckHealthAsync(); + health.Should().Be(true, "DaprClient is not healthy"); + // Start the workflow var startResponse = await daprClient.StartWorkflow(instanceID, workflowComponent, workflowType, input, workflowOptions, cts); From 3fa3012468160f4c5bbc790fec353362cc1c2b91 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Tue, 17 Jan 2023 16:05:35 -0700 Subject: [PATCH 06/29] Updating go version Signed-off-by: Ryan Lettieri --- .github/workflows/itests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/itests.yml b/.github/workflows/itests.yml index f1e20c598..8a6ac29c8 100644 --- a/.github/workflows/itests.yml +++ b/.github/workflows/itests.yml @@ -41,7 +41,7 @@ jobs: prefix: 'net6' env: NUPKG_OUTDIR: bin/Release/nugets - GOVER: 1.17 + GOVER: 1.19 GOOS: linux GOARCH: amd64 GOPROXY: https://proxy.golang.org From 211224d46a252344186f38083f0b3043e2ae17b8 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Tue, 17 Jan 2023 16:19:26 -0700 Subject: [PATCH 07/29] Adding in grpc endpoint for workflows test Signed-off-by: Ryan Lettieri --- test/Dapr.E2E.Test/Workflows/WorkflowTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs index 48317f883..a69f16df4 100644 --- a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs +++ b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs @@ -37,7 +37,7 @@ public async Task TestWorkflows() workflowOptions.Add("task_queue", "testQueue"); CancellationToken cts = new CancellationToken(); - using var daprClient = new DaprClientBuilder().Build(); + using var daprClient = new DaprClientBuilder().UseGrpcEndpoint(this.GrpcEndpoint).Build(); var health = daprClient.CheckHealthAsync(); health.Should().Be(true, "DaprClient is not healthy"); From 01f257cb05cd9e15b7278b9f8c2a5271a609f5ce Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Tue, 17 Jan 2023 16:32:18 -0700 Subject: [PATCH 08/29] Using http endpoint in workflows test Signed-off-by: Ryan Lettieri --- test/Dapr.E2E.Test/Workflows/WorkflowTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs index a69f16df4..ec956acae 100644 --- a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs +++ b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs @@ -37,9 +37,9 @@ public async Task TestWorkflows() workflowOptions.Add("task_queue", "testQueue"); CancellationToken cts = new CancellationToken(); - using var daprClient = new DaprClientBuilder().UseGrpcEndpoint(this.GrpcEndpoint).Build(); + using var daprClient = new DaprClientBuilder().UseHttpEndpoint(this.HttpEndpoint).Build(); - var health = daprClient.CheckHealthAsync(); + var health = await daprClient.CheckHealthAsync(); health.Should().Be(true, "DaprClient is not healthy"); // Start the workflow From 668801271f60d13d7766be5928289d9df34d9de0 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Tue, 17 Jan 2023 16:33:39 -0700 Subject: [PATCH 09/29] Using http endpoint in workflows test Signed-off-by: Ryan Lettieri --- test/Dapr.E2E.Test/Workflows/WorkflowTest.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs index ec956acae..51c2a8e81 100644 --- a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs +++ b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs @@ -37,8 +37,7 @@ public async Task TestWorkflows() workflowOptions.Add("task_queue", "testQueue"); CancellationToken cts = new CancellationToken(); - using var daprClient = new DaprClientBuilder().UseHttpEndpoint(this.HttpEndpoint).Build(); - + using var daprClient = new DaprClientBuilder().UseGrpcEndpoint(this.GrpcEndpoint).UseHttpEndpoint(this.HttpEndpoint).Build(); var health = await daprClient.CheckHealthAsync(); health.Should().Be(true, "DaprClient is not healthy"); From 68e145052c9e3b4a74fbf0427b8973fe3e2cb6ce Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Tue, 17 Jan 2023 16:48:14 -0700 Subject: [PATCH 10/29] Updating itest for testing with local dapr Signed-off-by: Ryan Lettieri --- .github/workflows/itests.yml | 2 +- src/Dapr.Client/Protos/dapr/proto/dapr/v1/dapr.proto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/itests.yml b/.github/workflows/itests.yml index 8a6ac29c8..1a1c5c1a1 100644 --- a/.github/workflows/itests.yml +++ b/.github/workflows/itests.yml @@ -69,7 +69,7 @@ jobs: uses: actions/checkout@v2 if: env.DAPR_REF != '' with: - repository: dapr/dapr + repository: RyanLettieri/dapr #TODO, REMOVE ONCE TESTING IS DONE ref: ${{ env.DAPR_REF }} path: dapr - name: Build and override dapr cli with referenced commit. diff --git a/src/Dapr.Client/Protos/dapr/proto/dapr/v1/dapr.proto b/src/Dapr.Client/Protos/dapr/proto/dapr/v1/dapr.proto index e464f91f9..82beabe87 100644 --- a/src/Dapr.Client/Protos/dapr/proto/dapr/v1/dapr.proto +++ b/src/Dapr.Client/Protos/dapr/proto/dapr/v1/dapr.proto @@ -697,7 +697,7 @@ message StartWorkflowRequest { string workflow_component = 2; string workflow_name = 3; map options = 4; - bytes input = 5; + bytes input = 5; } message TerminateWorkflowRequest { From f005729dcaf911284c965776e42cc2941bb3f7cd Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Tue, 17 Jan 2023 16:59:12 -0700 Subject: [PATCH 11/29] Updating ref used for testing Signed-off-by: Ryan Lettieri --- .github/workflows/itests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/itests.yml b/.github/workflows/itests.yml index 1a1c5c1a1..27f7e4ce0 100644 --- a/.github/workflows/itests.yml +++ b/.github/workflows/itests.yml @@ -49,7 +49,7 @@ jobs: DAPR_RUNTIME_VER: 1.9.5 DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/3dacfb672d55f1436c249057aaebbe597e1066f3/install/install.sh DAPR_CLI_REF: '' - DAPR_REF: '06e7559eb58d09564d485835c7e8b21f20630794' + DAPR_REF: '68159926dea9694f12a132c80935df0da92ae7bf' #TODO, REMOVE ONCE TESTING IS DONE steps: - name: Set up Dapr CLI run: wget -q ${{ env.DAPR_INSTALL_URL }} -O - | /bin/bash -s ${{ env.DAPR_CLI_VER }} From 3ba809f76956675006bcfa2057a35f8e138412f9 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Wed, 18 Jan 2023 16:09:42 -0700 Subject: [PATCH 12/29] Addressing more review comments and adding in serialization for input Signed-off-by: Ryan Lettieri --- src/Dapr.Client/DaprClient.cs | 2 +- src/Dapr.Client/DaprClientGrpc.cs | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Dapr.Client/DaprClient.cs b/src/Dapr.Client/DaprClient.cs index 7c4be1e26..b14a991fc 100644 --- a/src/Dapr.Client/DaprClient.cs +++ b/src/Dapr.Client/DaprClient.cs @@ -981,7 +981,7 @@ public abstract Task GetWorkflow( /// Identifier of the specific run. /// The component to interface with. /// A that can be used to cancel the operation. - /// A that will complete when the operation has completed. If the wrapped value is true the operation suceeded. + /// A that will complete when the terminate operation has been scheduled. If the wrapped value is true the operation suceeded. [Obsolete("This API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")] public abstract Task TerminateWorkflow( string instanceID, diff --git a/src/Dapr.Client/DaprClientGrpc.cs b/src/Dapr.Client/DaprClientGrpc.cs index 800bb9476..9cfe69edd 100644 --- a/src/Dapr.Client/DaprClientGrpc.cs +++ b/src/Dapr.Client/DaprClientGrpc.cs @@ -1389,19 +1389,21 @@ public async override Task StartWorkflow( ArgumentVerifier.ThrowIfNullOrEmpty(instanceId, nameof(instanceId)); ArgumentVerifier.ThrowIfNullOrEmpty(workflowComponent, nameof(workflowComponent)); ArgumentVerifier.ThrowIfNullOrEmpty(workflowType, nameof(workflowType)); - ArgumentVerifier.ThrowIfNull(workflowOptions, nameof(workflowOptions)); ArgumentVerifier.ThrowIfNull(input, nameof(input)); + // Serialize json data. Converts input object to json string and then bytestring inside the request. + string jsonUtf8Bytes =JsonSerializer.Serialize(input); + var request = new Autogenerated.StartWorkflowRequest() { InstanceId = instanceId, WorkflowComponent = workflowComponent, WorkflowName = workflowType, - Input = (ByteString)input + Input = ByteString.CopyFromUtf8(jsonUtf8Bytes) }; if (workflowOptions?.Count > 0) - { + { foreach (var item in workflowOptions) { request.Options[item.Key] = item.Value; @@ -1471,10 +1473,10 @@ public async override Task TerminateWorkflow( }; var options = CreateCallOptions(headers: null, cancellationToken); - Autogenerated.TerminateWorkflowResponse response = new Autogenerated.TerminateWorkflowResponse(); // RRL Do we need a response? + try { - response = await client.TerminateWorkflowAlpha1Async(request, options); + await client.TerminateWorkflowAlpha1Async(request, options); } catch (RpcException ex) { From 51e43498251f8f24df877fe27f2d2a9b7bbc64d4 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Thu, 19 Jan 2023 14:00:41 -0700 Subject: [PATCH 13/29] Addressing more review comments for workflow management SDK Signed-off-by: Ryan Lettieri --- src/Dapr.Client/DaprClientGrpc.cs | 3 ++- src/Dapr.Client/GetWorkflowResponse.cs | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Dapr.Client/DaprClientGrpc.cs b/src/Dapr.Client/DaprClientGrpc.cs index 9cfe69edd..b3b8a1577 100644 --- a/src/Dapr.Client/DaprClientGrpc.cs +++ b/src/Dapr.Client/DaprClientGrpc.cs @@ -1446,7 +1446,8 @@ public async override Task GetWorkflow( { var options = CreateCallOptions(headers: null, cancellationToken); var response = await client.GetWorkflowAlpha1Async(request, options); - return new GetWorkflowResponse(response.InstanceId, response.StartTime, response.Metadata); + var dateTimeValue = new DateTime(response.StartTime); + return new GetWorkflowResponse(response.InstanceId, dateTimeValue, response.Metadata); } catch (RpcException ex) { diff --git a/src/Dapr.Client/GetWorkflowResponse.cs b/src/Dapr.Client/GetWorkflowResponse.cs index bbacf819e..c5d2d917c 100644 --- a/src/Dapr.Client/GetWorkflowResponse.cs +++ b/src/Dapr.Client/GetWorkflowResponse.cs @@ -19,7 +19,7 @@ namespace Dapr.Client /// /// Represents the response from invoking a binding. /// - public sealed class GetWorkflowResponse + public sealed record GetWorkflowResponse { /// /// Initializes a new .` @@ -27,7 +27,7 @@ public sealed class GetWorkflowResponse /// The instance ID assocated with this response. /// The time at which the workflow started executing. /// The response metadata. - public GetWorkflowResponse(string instanceId, Int64 startTime, IReadOnlyDictionary metadata) + public GetWorkflowResponse(string instanceId, DateTime startTime, IReadOnlyDictionary metadata) { ArgumentVerifier.ThrowIfNull(instanceId, nameof(instanceId)); ArgumentVerifier.ThrowIfNull(startTime, nameof(startTime)); @@ -46,7 +46,7 @@ public GetWorkflowResponse(string instanceId, Int64 startTime, IReadOnlyDictiona /// /// Gets the time that the workflow started. /// - public Int64 StartTime { set; get; } + public DateTime StartTime { set; get; } /// /// Gets the response metadata from the associated workflow. This includes information such as start time and status of workflow. From aaf7dcc1d0bf8f3082c6d2df058a821496a160f9 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Fri, 20 Jan 2023 12:46:43 -0700 Subject: [PATCH 14/29] Using a record for getworkflow and using UTC time Signed-off-by: Ryan Lettieri --- src/Dapr.Client/DaprClientGrpc.cs | 2 +- src/Dapr.Client/GetWorkflowResponse.cs | 32 +------------------- test/Dapr.E2E.Test/Workflows/WorkflowTest.cs | 6 ++-- 3 files changed, 5 insertions(+), 35 deletions(-) diff --git a/src/Dapr.Client/DaprClientGrpc.cs b/src/Dapr.Client/DaprClientGrpc.cs index b3b8a1577..bd097ef05 100644 --- a/src/Dapr.Client/DaprClientGrpc.cs +++ b/src/Dapr.Client/DaprClientGrpc.cs @@ -1446,7 +1446,7 @@ public async override Task GetWorkflow( { var options = CreateCallOptions(headers: null, cancellationToken); var response = await client.GetWorkflowAlpha1Async(request, options); - var dateTimeValue = new DateTime(response.StartTime); + var dateTimeValue = new DateTime(response.StartTime, DateTimeKind.Utc); return new GetWorkflowResponse(response.InstanceId, dateTimeValue, response.Metadata); } catch (RpcException ex) diff --git a/src/Dapr.Client/GetWorkflowResponse.cs b/src/Dapr.Client/GetWorkflowResponse.cs index c5d2d917c..4622745c3 100644 --- a/src/Dapr.Client/GetWorkflowResponse.cs +++ b/src/Dapr.Client/GetWorkflowResponse.cs @@ -16,41 +16,11 @@ namespace Dapr.Client { - /// - /// Represents the response from invoking a binding. - /// - public sealed record GetWorkflowResponse - { /// /// Initializes a new .` /// /// The instance ID assocated with this response. /// The time at which the workflow started executing. /// The response metadata. - public GetWorkflowResponse(string instanceId, DateTime startTime, IReadOnlyDictionary metadata) - { - ArgumentVerifier.ThrowIfNull(instanceId, nameof(instanceId)); - ArgumentVerifier.ThrowIfNull(startTime, nameof(startTime)); - ArgumentVerifier.ThrowIfNull(metadata, nameof(metadata)); - - this.InstanceId = instanceId; - this.StartTime = startTime; - this.Metadata = metadata; - } - - /// - /// Gets the workflow instance ID assocated with this response. - /// - public string InstanceId { set; get; } - - /// - /// Gets the time that the workflow started. - /// - public DateTime StartTime { set; get; } - - /// - /// Gets the response metadata from the associated workflow. This includes information such as start time and status of workflow. - /// - public IReadOnlyDictionary Metadata { set; get; } - } + public record GetWorkflowResponse(string instanceId, DateTime startTime, IReadOnlyDictionary metadata); } diff --git a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs index 51c2a8e81..5592e75da 100644 --- a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs +++ b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs @@ -49,14 +49,14 @@ public async Task TestWorkflows() // GET INFO TEST var getResponse = await daprClient.GetWorkflow(instanceID, workflowComponent, workflowType); - getResponse.InstanceId.Should().Be("testInstance"); - getResponse.Metadata["status"].Should().Be("Running", "The workflow is not running when it is expected to be running"); + getResponse.instanceId.Should().Be("testInstance"); + getResponse.metadata["status"].Should().Be("Running", "The workflow is not running when it is expected to be running"); // TERMINATE TEST: await daprClient.TerminateWorkflow(instanceID, workflowComponent); getResponse = await daprClient.GetWorkflow(instanceID, workflowComponent, workflowType); - getResponse.Metadata["status"].Should().Be("Terminated", "The workflow is still running when it is expected to be terminated"); + getResponse.metadata["status"].Should().Be("Terminated", "The workflow is still running when it is expected to be terminated"); } From e086a4ac9d2a4fbc730cd7d53958fca039ab7b91 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Wed, 25 Jan 2023 01:43:20 -0700 Subject: [PATCH 15/29] Updating workflows SDK now that built in engine is present Signed-off-by: Ryan Lettieri --- .github/workflows/itests.yml | 2 +- src/Dapr.Workflow/Dapr.Workflow.csproj | 2 +- test/Dapr.E2E.Test/Workflows/WorkflowTest.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/itests.yml b/.github/workflows/itests.yml index 27f7e4ce0..98c0d16c8 100644 --- a/.github/workflows/itests.yml +++ b/.github/workflows/itests.yml @@ -49,7 +49,7 @@ jobs: DAPR_RUNTIME_VER: 1.9.5 DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/3dacfb672d55f1436c249057aaebbe597e1066f3/install/install.sh DAPR_CLI_REF: '' - DAPR_REF: '68159926dea9694f12a132c80935df0da92ae7bf' #TODO, REMOVE ONCE TESTING IS DONE + DAPR_REF: '5b19ddf1b0baa27bf5e784bd29196d134db156e8' #TODO, REMOVE ONCE TESTING IS DONE steps: - name: Set up Dapr CLI run: wget -q ${{ env.DAPR_INSTALL_URL }} -O - | /bin/bash -s ${{ env.DAPR_CLI_VER }} diff --git a/src/Dapr.Workflow/Dapr.Workflow.csproj b/src/Dapr.Workflow/Dapr.Workflow.csproj index 5c7bf8e98..28e4e2513 100644 --- a/src/Dapr.Workflow/Dapr.Workflow.csproj +++ b/src/Dapr.Workflow/Dapr.Workflow.csproj @@ -2,7 +2,7 @@ - net6 + netcoreapp3.1;net5;net6 enable Dapr.Workflow Dapr Workflow Authoring SDK diff --git a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs index 5592e75da..848157c7c 100644 --- a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs +++ b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs @@ -30,7 +30,7 @@ public partial class E2ETests public async Task TestWorkflows() { string instanceID = "testInstance"; - string workflowComponent = "testComponent"; + string workflowComponent = "dapr"; string workflowType = "PlaceOrder"; object input = ByteString.CopyFrom(0x01); Dictionary workflowOptions = new Dictionary(); From e49ef1be4734f40d95f871e4e0b3bcf8b3cf3268 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Wed, 25 Jan 2023 01:57:16 -0700 Subject: [PATCH 16/29] Formatting cleanup Signed-off-by: Ryan Lettieri --- src/Dapr.Client/DaprClientGrpc.cs | 2 +- test/Dapr.E2E.Test/Workflows/WorkflowTest.cs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Dapr.Client/DaprClientGrpc.cs b/src/Dapr.Client/DaprClientGrpc.cs index dad296a7d..a3ccd4ba8 100644 --- a/src/Dapr.Client/DaprClientGrpc.cs +++ b/src/Dapr.Client/DaprClientGrpc.cs @@ -1405,7 +1405,7 @@ public async override Task StartWorkflow( ArgumentVerifier.ThrowIfNull(input, nameof(input)); // Serialize json data. Converts input object to json string and then bytestring inside the request. - string jsonUtf8Bytes =JsonSerializer.Serialize(input); + string jsonUtf8Bytes = JsonSerializer.Serialize(input); var request = new Autogenerated.StartWorkflowRequest() { diff --git a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs index 848157c7c..d20b30e40 100644 --- a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs +++ b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs @@ -41,10 +41,8 @@ public async Task TestWorkflows() var health = await daprClient.CheckHealthAsync(); health.Should().Be(true, "DaprClient is not healthy"); - // Start the workflow + // START WORKFLOW TEST var startResponse = await daprClient.StartWorkflow(instanceID, workflowComponent, workflowType, input, workflowOptions, cts); - - // Get Request and validate startResponse.InstanceId.Should().Be("testInstance", "Instance ID was not correct"); // GET INFO TEST From cff18013a0d28c9c61aa39b81278313271c39c84 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Wed, 25 Jan 2023 03:40:20 -0700 Subject: [PATCH 17/29] adding in a sleep command to wait for engine to start Signed-off-by: Ryan Lettieri --- test/Dapr.E2E.Test/Workflows/WorkflowTest.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs index d20b30e40..e9266e90d 100644 --- a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs +++ b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs @@ -41,6 +41,8 @@ public async Task TestWorkflows() var health = await daprClient.CheckHealthAsync(); health.Should().Be(true, "DaprClient is not healthy"); + Thread.Sleep(10000); // Sleep for 10s to wait for engine to start + // START WORKFLOW TEST var startResponse = await daprClient.StartWorkflow(instanceID, workflowComponent, workflowType, input, workflowOptions, cts); startResponse.InstanceId.Should().Be("testInstance", "Instance ID was not correct"); @@ -50,7 +52,6 @@ public async Task TestWorkflows() getResponse.instanceId.Should().Be("testInstance"); getResponse.metadata["status"].Should().Be("Running", "The workflow is not running when it is expected to be running"); - // TERMINATE TEST: await daprClient.TerminateWorkflow(instanceID, workflowComponent); getResponse = await daprClient.GetWorkflow(instanceID, workflowComponent, workflowType); From bd8f2ea2440e9b023e44275013addaa9414a0508 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Thu, 26 Jan 2023 04:54:49 -0700 Subject: [PATCH 18/29] Testing new changes to workflow engine Signed-off-by: Ryan Lettieri --- .github/workflows/itests.yml | 2 +- src/Dapr.Client/DaprClientGrpc.cs | 4 ++-- test/Dapr.E2E.Test/Workflows/WorkflowTest.cs | 7 ++++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/itests.yml b/.github/workflows/itests.yml index 98c0d16c8..dd8faccc3 100644 --- a/.github/workflows/itests.yml +++ b/.github/workflows/itests.yml @@ -49,7 +49,7 @@ jobs: DAPR_RUNTIME_VER: 1.9.5 DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/3dacfb672d55f1436c249057aaebbe597e1066f3/install/install.sh DAPR_CLI_REF: '' - DAPR_REF: '5b19ddf1b0baa27bf5e784bd29196d134db156e8' #TODO, REMOVE ONCE TESTING IS DONE + DAPR_REF: 'cc396f36bd0d670a25aad1fe86e06e67a74397f7' #TODO, REMOVE ONCE TESTING IS DONE steps: - name: Set up Dapr CLI run: wget -q ${{ env.DAPR_INSTALL_URL }} -O - | /bin/bash -s ${{ env.DAPR_CLI_VER }} diff --git a/src/Dapr.Client/DaprClientGrpc.cs b/src/Dapr.Client/DaprClientGrpc.cs index a3ccd4ba8..274e9500c 100644 --- a/src/Dapr.Client/DaprClientGrpc.cs +++ b/src/Dapr.Client/DaprClientGrpc.cs @@ -1405,14 +1405,14 @@ public async override Task StartWorkflow( ArgumentVerifier.ThrowIfNull(input, nameof(input)); // Serialize json data. Converts input object to json string and then bytestring inside the request. - string jsonUtf8Bytes = JsonSerializer.Serialize(input); + byte[] jsonUtf8Bytes = JsonSerializer.SerializeToUtf8Bytes(input); var request = new Autogenerated.StartWorkflowRequest() { InstanceId = instanceId, WorkflowComponent = workflowComponent, WorkflowName = workflowType, - Input = ByteString.CopyFromUtf8(jsonUtf8Bytes) + Input = ByteString.CopyFrom(jsonUtf8Bytes), }; if (workflowOptions?.Count > 0) diff --git a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs index e9266e90d..2233fcdcc 100644 --- a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs +++ b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs @@ -29,7 +29,8 @@ public partial class E2ETests [Fact] public async Task TestWorkflows() { - string instanceID = "testInstance"; + Thread.Sleep(10000); // Sleep for 10s to wait for engine to start + string instanceID = "TestWorkflowInstanceID"; string workflowComponent = "dapr"; string workflowType = "PlaceOrder"; object input = ByteString.CopyFrom(0x01); @@ -45,11 +46,11 @@ public async Task TestWorkflows() // START WORKFLOW TEST var startResponse = await daprClient.StartWorkflow(instanceID, workflowComponent, workflowType, input, workflowOptions, cts); - startResponse.InstanceId.Should().Be("testInstance", "Instance ID was not correct"); + startResponse.InstanceId.Should().Be("TestWorkflowInstanceID", "Instance ID was not correct"); // GET INFO TEST var getResponse = await daprClient.GetWorkflow(instanceID, workflowComponent, workflowType); - getResponse.instanceId.Should().Be("testInstance"); + getResponse.instanceId.Should().Be("TestWorkflowInstanceID"); getResponse.metadata["status"].Should().Be("Running", "The workflow is not running when it is expected to be running"); // TERMINATE TEST: From 770f96eb07cd8489bb48ba9445ddf28c16ef6a87 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Thu, 26 Jan 2023 05:20:33 -0700 Subject: [PATCH 19/29] Updating comment Signed-off-by: Ryan Lettieri --- src/Dapr.Client/DaprClientGrpc.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Dapr.Client/DaprClientGrpc.cs b/src/Dapr.Client/DaprClientGrpc.cs index 274e9500c..a3032f14d 100644 --- a/src/Dapr.Client/DaprClientGrpc.cs +++ b/src/Dapr.Client/DaprClientGrpc.cs @@ -1404,7 +1404,7 @@ public async override Task StartWorkflow( ArgumentVerifier.ThrowIfNullOrEmpty(workflowType, nameof(workflowType)); ArgumentVerifier.ThrowIfNull(input, nameof(input)); - // Serialize json data. Converts input object to json string and then bytestring inside the request. + // Serialize json data. Converts input object to bytes and then bytestring inside the request. byte[] jsonUtf8Bytes = JsonSerializer.SerializeToUtf8Bytes(input); var request = new Autogenerated.StartWorkflowRequest() From fba845fc2f8d03422925ba9472ea45d0dab12014 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Thu, 26 Jan 2023 07:34:24 -0700 Subject: [PATCH 20/29] Updating checks for workflows E2E test Signed-off-by: Ryan Lettieri --- test/Dapr.E2E.Test/Workflows/WorkflowTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs index 2233fcdcc..b8f92c3db 100644 --- a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs +++ b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs @@ -51,12 +51,12 @@ public async Task TestWorkflows() // GET INFO TEST var getResponse = await daprClient.GetWorkflow(instanceID, workflowComponent, workflowType); getResponse.instanceId.Should().Be("TestWorkflowInstanceID"); - getResponse.metadata["status"].Should().Be("Running", "The workflow is not running when it is expected to be running"); + getResponse.metadata["dapr.workflow.runtime_status"].Should().Be("RUNNING", "The workflow is not running when it is expected to be running"); // TERMINATE TEST: await daprClient.TerminateWorkflow(instanceID, workflowComponent); getResponse = await daprClient.GetWorkflow(instanceID, workflowComponent, workflowType); - getResponse.metadata["status"].Should().Be("Terminated", "The workflow is still running when it is expected to be terminated"); + getResponse.metadata["dapr.workflow.runtime_status"].Should().Be("TERMINATED", "The workflow is still running when it is expected to be terminated"); } From f713701076c23d1873b497040f0eb99a004d7ce0 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Thu, 26 Jan 2023 07:51:34 -0700 Subject: [PATCH 21/29] adding sleep to wf activity so terminate can be called Signed-off-by: Ryan Lettieri --- test/Dapr.E2E.Test.App/Startup.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Dapr.E2E.Test.App/Startup.cs b/test/Dapr.E2E.Test.App/Startup.cs index 356a8d79d..0b2407e1c 100644 --- a/test/Dapr.E2E.Test.App/Startup.cs +++ b/test/Dapr.E2E.Test.App/Startup.cs @@ -70,6 +70,7 @@ public void ConfigureServices(IServiceCollection services) // Example of registering a "ShipProduct" workflow activity function options.RegisterActivity("ShipProduct", implementation: (context, input) => { + System.Threading.Thread.Sleep(10000); // sleep for 10s to allow the terminate command to come through return Task.FromResult($"We are shipping {input} to the customer using our hoard of drones!"); }); }); From 55856e212607b3ba1beffbf9c623c5da94f7ae43 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Thu, 26 Jan 2023 20:46:06 -0700 Subject: [PATCH 22/29] Removing temp changes to itests file Signed-off-by: Ryan Lettieri --- .github/workflows/itests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/itests.yml b/.github/workflows/itests.yml index 5eaa41a14..0012fbf66 100644 --- a/.github/workflows/itests.yml +++ b/.github/workflows/itests.yml @@ -49,7 +49,7 @@ jobs: DAPR_RUNTIME_VER: 1.9.5 DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/3dacfb672d55f1436c249057aaebbe597e1066f3/install/install.sh DAPR_CLI_REF: '' - DAPR_REF: 'cc396f36bd0d670a25aad1fe86e06e67a74397f7' #TODO, REMOVE ONCE TESTING IS DONE + DAPR_REF: '' steps: - name: Set up Dapr CLI run: wget -q ${{ env.DAPR_INSTALL_URL }} -O - | /bin/bash -s ${{ env.DAPR_CLI_VER }} @@ -69,7 +69,7 @@ jobs: uses: actions/checkout@v2 if: env.DAPR_REF != '' with: - repository: RyanLettieri/dapr #TODO, REMOVE ONCE TESTING IS DONE + repository: dapr/dapr ref: ${{ env.DAPR_REF }} path: dapr - name: Build and override dapr cli with referenced commit. From b737575bce896b937af8001516fb574898e31bc0 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Fri, 27 Jan 2023 00:14:45 -0700 Subject: [PATCH 23/29] Adding in commit ref from dapr dapr Signed-off-by: Ryan Lettieri --- .github/workflows/itests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/itests.yml b/.github/workflows/itests.yml index 0012fbf66..43bdba08b 100644 --- a/.github/workflows/itests.yml +++ b/.github/workflows/itests.yml @@ -49,7 +49,7 @@ jobs: DAPR_RUNTIME_VER: 1.9.5 DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/3dacfb672d55f1436c249057aaebbe597e1066f3/install/install.sh DAPR_CLI_REF: '' - DAPR_REF: '' + DAPR_REF: '7d58eb3b2bd6c29f925d9078374759fb1c0d9a04' steps: - name: Set up Dapr CLI run: wget -q ${{ env.DAPR_INSTALL_URL }} -O - | /bin/bash -s ${{ env.DAPR_CLI_VER }} From 43b2035e0f004173cab92ee91de1e1f99b44f3d5 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Fri, 27 Jan 2023 00:39:57 -0700 Subject: [PATCH 24/29] Adding in commit ref from dapr dapr Signed-off-by: Ryan Lettieri --- .github/workflows/itests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/itests.yml b/.github/workflows/itests.yml index 43bdba08b..b241562bf 100644 --- a/.github/workflows/itests.yml +++ b/.github/workflows/itests.yml @@ -49,7 +49,7 @@ jobs: DAPR_RUNTIME_VER: 1.9.5 DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/3dacfb672d55f1436c249057aaebbe597e1066f3/install/install.sh DAPR_CLI_REF: '' - DAPR_REF: '7d58eb3b2bd6c29f925d9078374759fb1c0d9a04' + DAPR_REF: '82e097134cdc7494c5c3be71bf80f7904d6db9ea' steps: - name: Set up Dapr CLI run: wget -q ${{ env.DAPR_INSTALL_URL }} -O - | /bin/bash -s ${{ env.DAPR_CLI_VER }} From aedece7c36e90195e68f6f04c18e2c99a963fdb8 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Fri, 27 Jan 2023 01:01:37 -0700 Subject: [PATCH 25/29] Blank commit to restart git run Signed-off-by: Ryan Lettieri --- src/Dapr.Client/DaprClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Dapr.Client/DaprClient.cs b/src/Dapr.Client/DaprClient.cs index 6826997bb..b50711014 100644 --- a/src/Dapr.Client/DaprClient.cs +++ b/src/Dapr.Client/DaprClient.cs @@ -997,7 +997,7 @@ public abstract Task StartWorkflow( /// /// Attempt to get information about the given workflow. /// - /// Identifier of the specific run. + /// Identifier of the workflow specific run. /// The component to interface with. /// Name of the workflow to run. /// A that can be used to cancel the operation. From 654b5e4ec7881cd67125c43f4267c8e6ae9347be Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Fri, 27 Jan 2023 02:07:15 -0700 Subject: [PATCH 26/29] Addressing review comments Signed-off-by: Ryan Lettieri --- src/Dapr.Client/DaprClient.cs | 26 ++++++++++---------- src/Dapr.Client/DaprClientGrpc.cs | 25 +++++++++---------- src/Dapr.Client/GetWorkflowResponse.cs | 4 +-- src/Dapr.Workflow/Dapr.Workflow.csproj | 2 +- test/Dapr.E2E.Test.App/Startup.cs | 2 +- test/Dapr.E2E.Test/Workflows/WorkflowTest.cs | 15 +++++------ 6 files changed, 35 insertions(+), 39 deletions(-) diff --git a/src/Dapr.Client/DaprClient.cs b/src/Dapr.Client/DaprClient.cs index b50711014..29f0d9b3f 100644 --- a/src/Dapr.Client/DaprClient.cs +++ b/src/Dapr.Client/DaprClient.cs @@ -978,18 +978,18 @@ public abstract Task Unlock( /// /// Attempt to start the given workflow with response indicating success. /// - /// Identifier of the specific run. + /// Identifier of the specific run. /// The component to interface with. - /// Name of the workflow to run. + /// Name of the workflow to run. /// The list of options that are potentially needed to start a workflow. /// The input input for the given workflow. /// A that can be used to cancel the operation. /// A containing a [Obsolete("This API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")] - public abstract Task StartWorkflow( - string instanceID, + public abstract Task StartWorkflowAsync( + string instanceId, string workflowComponent, - string workflowType, + string workflowName, Object input, IReadOnlyDictionary workflowOptions = default, CancellationToken cancellationToken = default); @@ -997,28 +997,28 @@ public abstract Task StartWorkflow( /// /// Attempt to get information about the given workflow. /// - /// Identifier of the workflow specific run. + /// The unique ID of the target workflow instance. /// The component to interface with. - /// Name of the workflow to run. + /// Name of the workflow to run. /// A that can be used to cancel the operation. /// A containing a [Obsolete("This API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")] - public abstract Task GetWorkflow( - string instanceID, + public abstract Task GetWorkflowAsync( + string instanceId, string workflowComponent, - string workflowType, + string workflowName, CancellationToken cancellationToken = default); /// /// Attempt to get terminate the given workflow. /// - /// Identifier of the specific run. + /// The unique ID of the target workflow instance. /// The component to interface with. /// A that can be used to cancel the operation. /// A that will complete when the terminate operation has been scheduled. If the wrapped value is true the operation suceeded. [Obsolete("This API is currently not stable as it is in the Alpha stage. This attribute will be removed once it is stable.")] - public abstract Task TerminateWorkflow( - string instanceID, + public abstract Task TerminateWorkflowAsync( + string instanceId, string workflowComponent, CancellationToken cancellationToken = default); diff --git a/src/Dapr.Client/DaprClientGrpc.cs b/src/Dapr.Client/DaprClientGrpc.cs index 98bf5f1ab..b5b0774a8 100644 --- a/src/Dapr.Client/DaprClientGrpc.cs +++ b/src/Dapr.Client/DaprClientGrpc.cs @@ -1466,17 +1466,17 @@ public async override Task Unlock( #region Workflow API /// [Obsolete] - public async override Task StartWorkflow( + public async override Task StartWorkflowAsync( string instanceId, string workflowComponent, - string workflowType, + string workflowName, Object input, IReadOnlyDictionary workflowOptions = default, CancellationToken cancellationToken = default) { ArgumentVerifier.ThrowIfNullOrEmpty(instanceId, nameof(instanceId)); ArgumentVerifier.ThrowIfNullOrEmpty(workflowComponent, nameof(workflowComponent)); - ArgumentVerifier.ThrowIfNullOrEmpty(workflowType, nameof(workflowType)); + ArgumentVerifier.ThrowIfNullOrEmpty(workflowName, nameof(workflowName)); ArgumentVerifier.ThrowIfNull(input, nameof(input)); // Serialize json data. Converts input object to bytes and then bytestring inside the request. @@ -1486,12 +1486,12 @@ public async override Task StartWorkflow( { InstanceId = instanceId, WorkflowComponent = workflowComponent, - WorkflowName = workflowType, + WorkflowName = workflowName, Input = ByteString.CopyFrom(jsonUtf8Bytes), }; if (workflowOptions?.Count > 0) - { + { foreach (var item in workflowOptions) { request.Options[item.Key] = item.Value; @@ -1513,21 +1513,20 @@ public async override Task StartWorkflow( /// [Obsolete] - public async override Task GetWorkflow( + public async override Task GetWorkflowAsync( string instanceId, string workflowComponent, - string workflowType, + string workflowName, CancellationToken cancellationToken = default) { ArgumentVerifier.ThrowIfNullOrEmpty(instanceId, nameof(instanceId)); ArgumentVerifier.ThrowIfNullOrEmpty(workflowComponent, nameof(workflowComponent)); - ArgumentVerifier.ThrowIfNullOrEmpty(workflowType, nameof(workflowType)); var request = new Autogenerated.GetWorkflowRequest() { InstanceId = instanceId, WorkflowComponent = workflowComponent, - WorkflowType = workflowType + WorkflowType = workflowName //TODO: Change 'WorkflowType' to 'WorkflowName' once changes go through dapr/dapr }; try @@ -1547,17 +1546,17 @@ public async override Task GetWorkflow( /// [Obsolete] - public async override Task TerminateWorkflow( - string instanceID, + public async override Task TerminateWorkflowAsync( + string instanceId, string workflowComponent, CancellationToken cancellationToken = default) { - ArgumentVerifier.ThrowIfNullOrEmpty(instanceID, nameof(instanceID)); + ArgumentVerifier.ThrowIfNullOrEmpty(instanceId, nameof(instanceId)); ArgumentVerifier.ThrowIfNullOrEmpty(workflowComponent, nameof(workflowComponent)); var request = new Autogenerated.TerminateWorkflowRequest() { - InstanceId = instanceID, + InstanceId = instanceId, WorkflowComponent = workflowComponent }; diff --git a/src/Dapr.Client/GetWorkflowResponse.cs b/src/Dapr.Client/GetWorkflowResponse.cs index 4622745c3..408a52592 100644 --- a/src/Dapr.Client/GetWorkflowResponse.cs +++ b/src/Dapr.Client/GetWorkflowResponse.cs @@ -17,10 +17,10 @@ namespace Dapr.Client { /// - /// Initializes a new .` + /// Initializes a new . /// /// The instance ID assocated with this response. /// The time at which the workflow started executing. /// The response metadata. - public record GetWorkflowResponse(string instanceId, DateTime startTime, IReadOnlyDictionary metadata); + public record GetWorkflowResponse(string instanceId, DateTime startTime, IReadOnlyDictionary metadata); } diff --git a/src/Dapr.Workflow/Dapr.Workflow.csproj b/src/Dapr.Workflow/Dapr.Workflow.csproj index 28e4e2513..48a57eb17 100644 --- a/src/Dapr.Workflow/Dapr.Workflow.csproj +++ b/src/Dapr.Workflow/Dapr.Workflow.csproj @@ -2,7 +2,7 @@ - netcoreapp3.1;net5;net6 + netcoreapp3.1;net6;net7 enable Dapr.Workflow Dapr Workflow Authoring SDK diff --git a/test/Dapr.E2E.Test.App/Startup.cs b/test/Dapr.E2E.Test.App/Startup.cs index 0b2407e1c..14e1358d5 100644 --- a/test/Dapr.E2E.Test.App/Startup.cs +++ b/test/Dapr.E2E.Test.App/Startup.cs @@ -18,6 +18,7 @@ namespace Dapr.E2E.Test using Dapr.E2E.Test.Actors.Timers; using Dapr.E2E.Test.Actors.ExceptionTesting; using Dapr.E2E.Test.App.ErrorTesting; + using Dapr.Workflow; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; @@ -25,7 +26,6 @@ namespace Dapr.E2E.Test using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; - using Dapr.Workflow; using System.Threading.Tasks; /// diff --git a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs index b8f92c3db..9ce2b0b16 100644 --- a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs +++ b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs @@ -29,10 +29,9 @@ public partial class E2ETests [Fact] public async Task TestWorkflows() { - Thread.Sleep(10000); // Sleep for 10s to wait for engine to start - string instanceID = "TestWorkflowInstanceID"; + string instanceId = "TestWorkflowInstanceID"; string workflowComponent = "dapr"; - string workflowType = "PlaceOrder"; + string workflowName = "PlaceOrder"; object input = ByteString.CopyFrom(0x01); Dictionary workflowOptions = new Dictionary(); workflowOptions.Add("task_queue", "testQueue"); @@ -42,20 +41,18 @@ public async Task TestWorkflows() var health = await daprClient.CheckHealthAsync(); health.Should().Be(true, "DaprClient is not healthy"); - Thread.Sleep(10000); // Sleep for 10s to wait for engine to start - // START WORKFLOW TEST - var startResponse = await daprClient.StartWorkflow(instanceID, workflowComponent, workflowType, input, workflowOptions, cts); + var startResponse = await daprClient.StartWorkflowAsync(instanceId, workflowComponent, workflowName, input, workflowOptions, cts); startResponse.InstanceId.Should().Be("TestWorkflowInstanceID", "Instance ID was not correct"); // GET INFO TEST - var getResponse = await daprClient.GetWorkflow(instanceID, workflowComponent, workflowType); + var getResponse = await daprClient.GetWorkflowAsync(instanceId, workflowComponent, workflowName); getResponse.instanceId.Should().Be("TestWorkflowInstanceID"); getResponse.metadata["dapr.workflow.runtime_status"].Should().Be("RUNNING", "The workflow is not running when it is expected to be running"); // TERMINATE TEST: - await daprClient.TerminateWorkflow(instanceID, workflowComponent); - getResponse = await daprClient.GetWorkflow(instanceID, workflowComponent, workflowType); + await daprClient.TerminateWorkflowAsync(instanceId, workflowComponent); + getResponse = await daprClient.GetWorkflowAsync(instanceId, workflowComponent, workflowName); getResponse.metadata["dapr.workflow.runtime_status"].Should().Be("TERMINATED", "The workflow is still running when it is expected to be terminated"); } From 49a0c94b3a82d32e82233acc96cedae04d018d34 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Fri, 27 Jan 2023 02:34:27 -0700 Subject: [PATCH 27/29] Adding in more verbose error logging Signed-off-by: Ryan Lettieri --- test/Dapr.E2E.Test/Workflows/WorkflowTest.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs index 9ce2b0b16..c5327fe34 100644 --- a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs +++ b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs @@ -43,17 +43,19 @@ public async Task TestWorkflows() // START WORKFLOW TEST var startResponse = await daprClient.StartWorkflowAsync(instanceId, workflowComponent, workflowName, input, workflowOptions, cts); - startResponse.InstanceId.Should().Be("TestWorkflowInstanceID", "Instance ID was not correct"); + startResponse.InstanceId.Should().Be("TestWorkflowInstanceID", "Instance ID $(startResponse.InstanceId) was not correct"); // GET INFO TEST var getResponse = await daprClient.GetWorkflowAsync(instanceId, workflowComponent, workflowName); getResponse.instanceId.Should().Be("TestWorkflowInstanceID"); - getResponse.metadata["dapr.workflow.runtime_status"].Should().Be("RUNNING", "The workflow is not running when it is expected to be running"); + getResponse.metadata["dapr.workflow.runtime_status"].Should().Be("RUNNING", "The workflow has a status of $(var) when it is expected to be running", + getResponse.metadata["dapr.workflow.runtime_status"]); // TERMINATE TEST: await daprClient.TerminateWorkflowAsync(instanceId, workflowComponent); getResponse = await daprClient.GetWorkflowAsync(instanceId, workflowComponent, workflowName); - getResponse.metadata["dapr.workflow.runtime_status"].Should().Be("TERMINATED", "The workflow is still running when it is expected to be terminated"); + getResponse.metadata["dapr.workflow.runtime_status"].Should().Be("TERMINATED", "The workflow has a status of $(var) when it is expected to be terminated", + getResponse.metadata["dapr.workflow.runtime_status"]); } From 09e6bbfdf87d542843c4cab4fa854347cbe3b32f Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Sun, 29 Jan 2023 21:56:55 -0700 Subject: [PATCH 28/29] Fixing string interpolation in workflows test Signed-off-by: Ryan Lettieri --- test/Dapr.E2E.Test/Workflows/WorkflowTest.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs index c5327fe34..91a2f7c45 100644 --- a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs +++ b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs @@ -43,19 +43,17 @@ public async Task TestWorkflows() // START WORKFLOW TEST var startResponse = await daprClient.StartWorkflowAsync(instanceId, workflowComponent, workflowName, input, workflowOptions, cts); - startResponse.InstanceId.Should().Be("TestWorkflowInstanceID", "Instance ID $(startResponse.InstanceId) was not correct"); + startResponse.InstanceId.Should().Be("TestWorkflowInstanceID", $"Instance ID {startResponse.InstanceId} was not correct"); // GET INFO TEST var getResponse = await daprClient.GetWorkflowAsync(instanceId, workflowComponent, workflowName); getResponse.instanceId.Should().Be("TestWorkflowInstanceID"); - getResponse.metadata["dapr.workflow.runtime_status"].Should().Be("RUNNING", "The workflow has a status of $(var) when it is expected to be running", - getResponse.metadata["dapr.workflow.runtime_status"]); + getResponse.metadata["dapr.workflow.runtime_status"].Should().Be("RUNNING", $"Instance ID {getResponse.metadata[\"dapr.workflow.runtime_status\"]} was not correct"); // TERMINATE TEST: await daprClient.TerminateWorkflowAsync(instanceId, workflowComponent); getResponse = await daprClient.GetWorkflowAsync(instanceId, workflowComponent, workflowName); - getResponse.metadata["dapr.workflow.runtime_status"].Should().Be("TERMINATED", "The workflow has a status of $(var) when it is expected to be terminated", - getResponse.metadata["dapr.workflow.runtime_status"]); + getResponse.metadata["dapr.workflow.runtime_status"].Should().Be("TERMINATED", $"Instance ID {getResponse.metadata[\"dapr.workflow.runtime_status\"]} was not correct"); } From 938e3493e531f5aa919470a88789224dec08eb85 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri Date: Sun, 29 Jan 2023 22:02:44 -0700 Subject: [PATCH 29/29] Fixing string interpolation Signed-off-by: Ryan Lettieri --- test/Dapr.E2E.Test/Workflows/WorkflowTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs index 91a2f7c45..b5421b999 100644 --- a/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs +++ b/test/Dapr.E2E.Test/Workflows/WorkflowTest.cs @@ -48,12 +48,12 @@ public async Task TestWorkflows() // GET INFO TEST var getResponse = await daprClient.GetWorkflowAsync(instanceId, workflowComponent, workflowName); getResponse.instanceId.Should().Be("TestWorkflowInstanceID"); - getResponse.metadata["dapr.workflow.runtime_status"].Should().Be("RUNNING", $"Instance ID {getResponse.metadata[\"dapr.workflow.runtime_status\"]} was not correct"); + getResponse.metadata["dapr.workflow.runtime_status"].Should().Be("RUNNING", $"Instance ID {getResponse.metadata["dapr.workflow.runtime_status"]} was not correct"); // TERMINATE TEST: await daprClient.TerminateWorkflowAsync(instanceId, workflowComponent); getResponse = await daprClient.GetWorkflowAsync(instanceId, workflowComponent, workflowName); - getResponse.metadata["dapr.workflow.runtime_status"].Should().Be("TERMINATED", $"Instance ID {getResponse.metadata[\"dapr.workflow.runtime_status\"]} was not correct"); + getResponse.metadata["dapr.workflow.runtime_status"].Should().Be("TERMINATED", $"Instance ID {getResponse.metadata["dapr.workflow.runtime_status"]} was not correct"); }