public async Task Simultaneous() { await SyncContext.Clear; // We're going to establish two simultaneous client connections, // register a workflow on each, and then verify that these workflows work. var client1Settings = fixture.Settings.Clone(); client1Settings.TaskQueue = "taskqueue-1"; using (var client1 = await TemporalClient.ConnectAsync(client1Settings)) { var worker1 = await client1.NewWorkerAsync(); await worker1.RegisterWorkflowAsync <WorkflowWithResult1>(); await worker1.StartAsync(); var client2Settings = fixture.Settings.Clone(); client2Settings.TaskQueue = "taskqueue-2"; using (var client2 = await TemporalClient.ConnectAsync(client2Settings)) { var worker2 = await client2.NewWorkerAsync(); await worker2.RegisterWorkflowAsync <WorkflowWithResult2>(); await worker2.StartAsync(); var options1 = new StartWorkflowOptions() { TaskQueue = "taskqueue-1" }; var options2 = new StartWorkflowOptions() { TaskQueue = "taskqueue-2" }; var stub1 = client1.NewWorkflowStub <IWorkflowWithResult1>(options: options1); var stub2 = client2.NewWorkflowStub <IWorkflowWithResult2>(options: options2); Assert.Equal("WF1 says: Hello Jeff!", await stub1.HelloAsync("Jeff")); Assert.Equal("WF2 says: Hello Jeff!", await stub2.HelloAsync("Jeff")); } } }
public async Task Workflow_ExternalIdNoReuse() { await SyncContext.Clear; // Verify that default Cadence settings allow duplicate workflow IDs // and then change this to prevent reuse. var settings = fixture.Settings.Clone(); Assert.Equal(WorkflowIdReusePolicy.AllowDuplicate, settings.WorkflowIdReusePolicy); settings.WorkflowIdReusePolicy = WorkflowIdReusePolicy.RejectDuplicate; using (var client = await TemporalClient.ConnectAsync(settings)) { // Create a worker and register the workflow and activity // implementations to let Temporal know we're open for business. var worker = client.NewWorkerAsync().Result; worker.RegisterAssemblyAsync(Assembly.GetExecutingAssembly()).WaitWithoutAggregate(); worker.StartAsync().WaitWithoutAggregate(); // Do the first run; this should succeed. var options = new StartWorkflowOptions() { Id = $"Workflow_ExternalIdNoReuse-{Guid.NewGuid().ToString("d")}" }; var stub = client.NewWorkflowStub <IWorkflowIdReuse>(options); Assert.Equal("Hello Jack!", await stub.HelloAsync("Jack")); // Do the second run with the same ID. This shouldn't actually start // another workflow and will return the result from the original // workflow instead. stub = client.NewWorkflowStub <IWorkflowIdReuse>(options); Assert.Equal("Hello Jack!", await stub.HelloAsync("Jill")); } }
public async Task Workflow_ExternalIdReuseViaSettings() { await SyncContext.Clear; // Verify that default Cadence settings allow duplicate workflow IDs. var settings = fixture.Settings.Clone(); Assert.Equal(WorkflowIdReusePolicy.AllowDuplicate, settings.WorkflowIdReusePolicy); using (var client = await TemporalClient.ConnectAsync(settings)) { // Create a worker and register the workflow and activity // implementations to let Temporal know we're open for business. var worker = client.NewWorkerAsync().Result; worker.RegisterAssemblyAsync(Assembly.GetExecutingAssembly()).WaitWithoutAggregate(); worker.StartAsync().WaitWithoutAggregate(); // Do the first run. var options = new StartWorkflowOptions() { Id = $"Workflow_ExternalIdReuseViaOptions-{Guid.NewGuid().ToString("d")}" }; var stub = client.NewWorkflowStub <IWorkflowIdReuse>(options); Assert.Equal("Hello Jack!", await stub.HelloAsync("Jack")); // Do the second run. stub = client.NewWorkflowStub <IWorkflowIdReuse>(options); Assert.Equal("Hello Jill!", await stub.HelloAsync("Jill")); } }
/// <summary> /// Creates a workflow stub instance suitable for starting a new external workflow. /// </summary> /// <param name="client">The associated <see cref="TemporalClient"/>.</param> /// <param name="dataConverter">The data converter.</param> /// <param name="workflowTypeName">Specifies the workflow type name.</param> /// <param name="options">Specifies the <see cref="StartWorkflowOptions"/> or <c>null</c>.</param> /// <param name="workflowInterface">Specifies the workflow interface definition.</param> /// <returns>The workflow stub as an <see cref="object"/>.</returns> public object Create(TemporalClient client, IDataConverter dataConverter, string workflowTypeName, StartWorkflowOptions options, System.Type workflowInterface) { Covenant.Requires <ArgumentNullException>(client != null, nameof(client)); Covenant.Requires <ArgumentNullException>(dataConverter != null, nameof(dataConverter)); Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(workflowTypeName), nameof(workflowTypeName)); Covenant.Requires <ArgumentNullException>(workflowInterface != null, nameof(workflowInterface)); options = options ?? new StartWorkflowOptions(); return(externalStartConstructor.Invoke(new object[] { client, dataConverter, workflowTypeName, options, workflowInterface })); }
public async Task Interop_Workflow_Untyped() { await SyncContext.Clear; // verify that we can execute a GOLANG workflows using // untyped stubs. using (new TwfArgsWorker()) { //----------------------------------------- // Zero args: var options = new StartWorkflowOptions() { Id = "NoArgs-" + Guid.NewGuid().ToString("d"), TaskQueue = TemporalTestHelper.TaskQueue_TwfArgs }; var stub = client.NewUntypedWorkflowStub("NoArgsWorkflow", options); var execution = await stub.StartAsync(); Assert.Equal("Hello there!", await stub.GetResultAsync <string>()); //----------------------------------------- // One arg: options = new StartWorkflowOptions() { Id = "OneArg-" + Guid.NewGuid().ToString("d"), TaskQueue = TemporalTestHelper.TaskQueue_TwfArgs }; stub = client.NewUntypedWorkflowStub("OneArgWorkflow", options); execution = await stub.StartAsync("JACK"); Assert.Equal("Hello JACK!", await stub.GetResultAsync <string>()); //----------------------------------------- // Two Args: options = new StartWorkflowOptions() { Id = "TwoArgs-" + Guid.NewGuid().ToString("d"), TaskQueue = TemporalTestHelper.TaskQueue_TwfArgs }; stub = client.NewUntypedWorkflowStub("TwoArgsWorkflow", options); execution = await stub.StartAsync("JACK", "JILL"); Assert.Equal("Hello JACK & JILL!", await stub.GetResultAsync <string>()); //----------------------------------------- // One Array Arg: options = new StartWorkflowOptions() { Id = "OneArrayArg-" + Guid.NewGuid().ToString("d"), TaskQueue = TemporalTestHelper.TaskQueue_TwfArgs }; stub = client.NewUntypedWorkflowStub("ArrayArgWorkflow", options); execution = await stub.StartAsync(new int[] { 0, 1, 2, 3, 4 }); var arrayResult = await stub.GetResultAsync <int[]>(); Assert.Equal(new int[] { 0, 1, 2, 3, 4 }, arrayResult); //----------------------------------------- // One Array and a String Arg options = new StartWorkflowOptions() { Id = "OneArrayArgs-" + Guid.NewGuid().ToString("d"), TaskQueue = TemporalTestHelper.TaskQueue_TwfArgs }; stub = client.NewUntypedWorkflowStub("ArrayArgsWorkflow", options); execution = await stub.StartAsync(new int[] { 0, 1, 2, 3, 4 }, "test"); arrayResult = await stub.GetResultAsync <int[]>(); Assert.Equal(new int[] { 0, 1, 2, 3, 4 }, arrayResult); //----------------------------------------- // Workflow that returns just an error: // Verify that things work when the workflow DOESN'T return an error. options = new StartWorkflowOptions() { Id = "ErrorWorkflow-NOERROR-" + Guid.NewGuid().ToString("d"), TaskQueue = TemporalTestHelper.TaskQueue_TwfArgs }; stub = client.NewUntypedWorkflowStub("ErrorWorkflow", options); execution = await stub.StartAsync(""); await stub.GetResultAsync(); // Verify that things work when the workflow DOES return an error. options = new StartWorkflowOptions() { Id = "ErrorWorkflow-ERROR-" + Guid.NewGuid().ToString("d"), TaskQueue = TemporalTestHelper.TaskQueue_TwfArgs }; stub = client.NewUntypedWorkflowStub("ErrorWorkflow", options); execution = await stub.StartAsync("error message"); try { await stub.GetResultAsync(); } catch (TemporalGenericException e) { Assert.Equal("error message", e.Reason); } catch (Exception e) { Assert.True(false, $"Expected [{typeof(TemporalGenericException).FullName}] not [{e.GetType().FullName}]."); } //----------------------------------------- // Workflow that returns a string or an error: // Verify that things work when the workflow DOESN'T return an error. options = new StartWorkflowOptions() { Id = "StringErrorWorkflow-NOERROR-" + Guid.NewGuid().ToString("d"), TaskQueue = TemporalTestHelper.TaskQueue_TwfArgs }; stub = client.NewUntypedWorkflowStub("StringErrorWorkflow", options); execution = await stub.StartAsync("JEFF", ""); Assert.Equal("Hello JEFF!", await stub.GetResultAsync <string>()); // Verify that things work when the workflow DOES return an error. options = new StartWorkflowOptions() { Id = "StringErrorWorkflow-ERROR-" + Guid.NewGuid().ToString("d"), TaskQueue = TemporalTestHelper.TaskQueue_TwfArgs }; stub = client.NewUntypedWorkflowStub("ErrorWorkflow", options); execution = await stub.StartAsync("", "error message"); try { await stub.GetResultAsync <string>(); } catch (Exception e) { Assert.Equal("error message", e.Message); } } }