public static async Task Main(string[] args) { // Connect to Cadence var settings = new CadenceSettings() { DefaultDomain = "my-domain", CreateDomain = true, Servers = new List <string>() { "cadence://localhost:7933" } }; using (var client = await CadenceClient.ConnectAsync(settings)) { // Register your workflow and activity implementations to let // Cadence know we're open for business. await client.RegisterAssemblyAsync(System.Reflection.Assembly.GetExecutingAssembly()); await client.StartWorkerAsync("my-tasks"); // Invoke the workflow. var workflowStub = client.NewWorkflowStub <IEmailWorkflow>(); await workflowStub.SendMessagesAsync(); } }
public static async Task Main(string[] args) { try { var settings = new CadenceSettings("cadence://localhost:7933") { DefaultDomain = "test-domain", CreateDomain = true }; using (var client = await CadenceClient.ConnectAsync(settings)) { await client.RegisterAssemblyAsync(Assembly.GetExecutingAssembly()); await client.StartWorkerAsync(taskList : "hello-tasks"); //------------------------------------- // Submit an order to: IOrderWorkflow1 var stub1 = client.NewWorkflowStub <IOrderWorkflow1>(); var orderTask1 = stub1.ProcessAsync(); // Attempt to cancel it via a synchronous signal. var cancelled1 = await stub1.CancelAsync(); // Wait for order processing to complete. The result will // be FALSE if the order was cancelled. var result1 = await orderTask1; //------------------------------------- // Submit an order to: IOrderWorkflow2 var stub2 = client.NewWorkflowStub <IOrderWorkflow2>(); var orderTask2 = stub2.ProcessAsync(); // Attempt to cancel it via a synchronous signal. var cancelled2 = await stub2.CancelAsync(); // Wait for order processing to complete. The result will // be FALSE if the order was cancelled. var result2 = await orderTask2; //------------------------------------- Console.WriteLine($"RESULT-1: {result1}"); Console.WriteLine($"RESULT-2: {result2}"); } } catch (ConnectException) { Console.Error.WriteLine("Cannot connect to Cadence. Be sure you've started a"); Console.Error.WriteLine("local Cadence Docker container via:"); Console.Error.WriteLine(); Console.Error.WriteLine("docker run --detach --name cadence-dev -p 7933-7939:7933-7939 -p 8088:8088 nkubeio/cadence-dev"); } }
public async Task Connect_Twice() { await SyncContext.Clear; // We're going to establish two successive client connections // and verify that these work. using (var client = await CadenceClient.ConnectAsync(fixture.Settings)) { await client.RegisterWorkflowAsync <WorkflowWithResult3>(); using (await client.StartWorkerAsync("tasklist-3")) { var stub1 = client.NewWorkflowStub <IWorkflowWithResult3>(); Assert.Equal("WF3 says: Hello Jack!", await stub1.HelloAsync("Jack")); } } using (var client = await CadenceClient.ConnectAsync(fixture.Settings)) { await client.RegisterWorkflowAsync <WorkflowWithResult4>(); using (await client.StartWorkerAsync("tasklist-4")) { var stub1 = client.NewWorkflowStub <IWorkflowWithResult4>(); Assert.Equal("WF4 says: Hello Jack!", await stub1.HelloAsync("Jack")); } } }
public static async Task Main(string[] args) { try { var settings = new CadenceSettings("cadence://localhost:7933") { DefaultDomain = "test-domain", CreateDomain = true }; using (var client = await CadenceClient.ConnectAsync(settings)) { await client.RegisterAssemblyAsync(Assembly.GetExecutingAssembly()); await client.StartWorkerAsync(taskList : "hello-tasks"); var stub = client.NewWorkflowStub <IHelloWorkflow>(); var result = await stub.HelloAsync("Sally"); Console.WriteLine($"RESULT: {result}"); } } catch (ConnectException) { Console.Error.WriteLine("Cannot connect to Cadence. Be sure you've started a"); Console.Error.WriteLine("local Cadence Docker container via:"); Console.Error.WriteLine(); Console.Error.WriteLine("docker run --detach --name cadence-dev -p 7933-7939:7933-7939 -p 8088:8088 nkubeio/cadence-dev"); } }
public async Task Workflow_ExternalIdNoReuse() { await SyncContext.ClearAsync; // Verify that default Cadence settings reject duplicate workflow IDs. Assert.Equal(WorkflowIdReusePolicy.AllowDuplicateFailedOnly, fixture.Settings.WorkflowIdReusePolicy); using (var client = await CadenceClient.ConnectAsync(fixture.Settings)) { await client.RegisterAssemblyAsync(Assembly.GetExecutingAssembly()); await client.StartWorkerAsync(CadenceTestHelper.TaskList); var options = new WorkflowOptions() { WorkflowId = $"Workflow_ExternalIdNoReuse-{Guid.NewGuid().ToString("d")}" }; // Do the first run; this should succeed. 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 static async Task Main(string[] args) { // Connect to Cadence var settings = new CadenceSettings() { DefaultDomain = "my-domain", CreateDomain = true, Servers = new List <string>() { "cadence://localhost:7933" } }; using (var client = await CadenceClient.ConnectAsync(settings)) { // Register your workflow implementation to let Cadence // know we're open for business. await client.RegisterWorkflowAsync <HelloWorkflow>(); await client.StartWorkerAsync("my-tasks"); // Invoke your workflow. var stub = client.NewWorkflowStub <IHelloWorkflow>(); Console.WriteLine(await stub.HelloAsync("Jeff")); } }
public static async Task Main(string[] args) { // Connect to Cadence var settings = new CadenceSettings() { DefaultDomain = "my-domain", CreateDomain = true, Servers = new List <string>() { "cadence://*****:*****@my-company.com", "Jeff"); } }
public async Task Workflow_ExternalIdReuseViaSettings() { await SyncContext.ClearAsync; // Verify that we can reuse a workflow ID for an external // workflow via client settings. var settings = fixture.Settings.Clone(); settings.WorkflowIdReusePolicy = WorkflowIdReusePolicy.AllowDuplicate; using (var client = await CadenceClient.ConnectAsync(settings)) { await client.RegisterAssemblyAsync(Assembly.GetExecutingAssembly()); await client.StartWorkerAsync(CadenceTestHelper.TaskList); var options = new WorkflowOptions() { WorkflowId = $"Workflow_ExternalIdReuseViaOptions-{Guid.NewGuid().ToString("d")}" }; // Do the first run. 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> /// Called when an already started fixture is being restarted. This /// establishes a fresh Cadence connection. /// </summary> public override void OnRestart() { if (keepConnection) { // We're going to continue using the same connection. return; } // Close any existing connection related objects. if (Connection != null) { Connection.Dispose(); Connection = null; } if (ConnectionClient != null) { ConnectionClient.Dispose(); ConnectionClient = null; } // Establish fresh connections. Connection = CadenceClient.ConnectAsync(settings).Result; ConnectionClient = new HttpClient() { BaseAddress = Connection.ListenUri }; }
public static async Task Main(string[] args) { var settings = new CadenceSettings() { DefaultDomain = "my-domain", CreateDomain = true, Servers = new List <string>() { "cadence://localhost:7933" } }; using (var client = await CadenceClient.ConnectAsync(settings)) { await client.RegisterAssemblyAsync(System.Reflection.Assembly.GetExecutingAssembly()); await client.StartWorkerAsync("my-tasks"); // Invoke the workflow and then query it's status a few times. var stub = client.NewWorkflowStub <IMyWorkflow>(); var task = stub.DoItAsync(); for (int i = 0; i < 5; i++) { await Task.Delay(TimeSpan.FromSeconds(2.5)); Console.WriteLine(await stub.GetStatusAsync()); } await task; } }
public Test_FixtureNoConnect(CadenceFixture fixture) { var settings = new CadenceSettings() { DefaultDomain = CadenceFixture.DefaultDomain, LogLevel = CadenceTestHelper.LogLevel, CreateDomain = true, Debug = CadenceTestHelper.Debug, DebugPrelaunched = CadenceTestHelper.DebugPrelaunched, DebugDisableHeartbeats = CadenceTestHelper.DebugDisableHeartbeats }; if (fixture.Start(settings, keepConnection: true, keepOpen: CadenceTestHelper.KeepCadenceServerOpen, noClient: true) == TestFixtureStatus.Started) { this.fixture = fixture; this.client = fixture.Client = CadenceClient.ConnectAsync(fixture.Settings).Result; // Auto register the test workflow and activity implementations. client.RegisterAssemblyAsync(Assembly.GetExecutingAssembly()).Wait(); // Start the worker. client.StartWorkerAsync(CadenceTestHelper.TaskList).Wait(); } else { this.fixture = fixture; this.client = fixture.Client; } }
public static async Task Main(string[] args) { // Connect to Cadence var settings = new CadenceSettings() { DefaultDomain = "my-domain", CreateDomain = true, Servers = new List <string>() { "cadence://localhost:7933" } }; using (var client = await CadenceClient.ConnectAsync(settings)) { var stub = client.NewWorkflowFutureStub <ICronWorkflow>( "backup", new WorkflowOptions() { // Run the workflow every day at 1:00am UTC: CronSchedule = "0 1 * * *" });; await stub.StartAsync(); } }
/// <summary> /// Used to start the fixture within a <see cref="ComposedFixture"/>. /// </summary> /// <param name="settings">Optional Cadence settings.</param> /// <param name="image">Optionally specifies the Cadence container image (defaults to <b>nkubeio/cadence-test:latest</b>).</param> /// <param name="name">Optionally specifies the Cadence container name (defaults to <c>cb-test</c>).</param> /// <param name="env">Optional environment variables to be passed to the Cadence container, formatted as <b>NAME=VALUE</b> or just <b>NAME</b>.</param> /// <param name="defaultDomain">Optionally specifies the default domain for the fixture's client. This defaults to <b>test-domain</b>.</param> /// <param name="defaultTaskList">Optionally specifies the default task list for the fixture's client. This defaults to <b>test-tasks</b>.</param> /// <param name="keepConnection"> /// Optionally specifies that a new Cadence connection <b>should not</b> be established for each /// unit test case. The same connection will be reused which will save about a second per test. /// </param> /// <param name="keepOpen"> /// Optionally indicates that the container should continue to run after the fixture is disposed. /// </param> /// <param name="emulateProxy"> /// <b>INTERNAL USE ONLY:</b> Optionally starts a partially functional integrated /// <b>cadence-proxy</b> for low-level testing. Most users should never enable this /// because it's probably not going to do what you expect. /// </param> /// <remarks> /// <note> /// A fresh Cadence client <see cref="Connection"/> will be established every time this /// fixture is started, regardless of whether the fixture has already been started. This /// ensures that each unit test will start with a client in the default state. /// </note> /// </remarks> public void StartAsComposed( CadenceSettings settings = null, string image = "nkubeio/cadence-test:latest", string name = "cadence-test", string[] env = null, string defaultDomain = DefaultDomain, string defaultTaskList = DefaultTaskList, bool keepConnection = false, bool keepOpen = false, bool emulateProxy = false) { Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(image)); base.CheckWithinAction(); if (!IsRunning) { // Start the fixture base.StartAsComposed(name, image, new string[] { "--detach", "-p", "7933-7939:7933-7939", "-p", "8088:8088" }, env: env, keepOpen: keepOpen); Thread.Sleep(warmupDelay); // Initialize the settings. settings = settings ?? new CadenceSettings() { CreateDomain = true, DefaultDomain = defaultDomain, DefaultTaskList = defaultTaskList }; settings.Servers.Clear(); settings.Servers.Add($"http://localhost:{NetworkPorts.Cadence}"); settings.Emulate = emulateProxy || settings.Emulate; this.settings = settings; this.keepConnection = keepConnection; // Establish the Cadence connection. Connection = CadenceClient.ConnectAsync(settings).Result; ConnectionClient = new HttpClient() { BaseAddress = Connection.ListenUri }; } }
public static async Task UntypedStub() { #region code_untyped var settings = new CadenceSettings() { // This specifies the default domain for operations initiated by the // client connected below (this can be overridden for specific // operations. DefaultDomain = "Acme-PROD", // Host/port for at least one of the Cadence cluster servers: Servers = new List <string>() { "cadence://*****:*****@lilltek.com", "Test subject", "This is a test email."); // Wait for the workflow to complete and return it's result. Note that we need // to explicitly specify the result [bool] type as a generic type parameter. // You need to ensure that this matches the workflow implementation as well. var success = await stub.GetResultAsync <bool>(); if (success) { Console.WriteLine("Email SENT!"); } else { Console.WriteLine("Email FAILED!"); } } #endregion }
public static async Task Main(string[] args) { // Initialize the logger. LogManager.Default.SetLogLevel("info"); logger = LogManager.Default.GetLogger(typeof(Program)); logger.LogInfo("Starting workflow service"); try { // Connect to Cadence var settings = new CadenceSettings() { DefaultDomain = "my-domain", CreateDomain = true, Servers = new List <string>() { "cadence://localhost:7933" } }; using (var client = await CadenceClient.ConnectAsync(settings)) { // Register your workflow and activity implementations to let // Cadence know we're open for business. await client.RegisterAssemblyAsync(System.Reflection.Assembly.GetExecutingAssembly()); await client.StartWorkerAsync("my-tasks"); // Spin forever, processing workflows and activities assigned by Cadence. while (true) { await Task.Delay(TimeSpan.FromMinutes(5)); } } } catch (Exception e) { logger.LogError(e); } finally { logger.LogInfo("Exiting workflow service"); } }
public static async Task Main(string[] args) { // Configure the settings name such that they will be injected // into the email activity when it's constructed. // // Note that we did this before calling RegisterAssemblyAsync() below. // Dependencies added after activities have been registered will be // ignored. NeonHelper.ServiceContainer.AddSingleton(typeof(MailSettings), new MailSettings() { MailServer = "mail.my-company.com" }); // Connect to Cadence var settings = new CadenceSettings() { DefaultDomain = "my-domain", CreateDomain = true, Servers = new List <string>() { "cadence://localhost:7933" } }; using (var client = await CadenceClient.ConnectAsync(settings)) { // Register your workflow and activity implementations to let // Cadence know we're open for business. await client.RegisterAssemblyAsync(System.Reflection.Assembly.GetExecutingAssembly()); await client.StartWorkerAsync("my-tasks"); // Invoke the workflow. var workflowStub = client.NewWorkflowStub <IEmailWorkflow>(); await workflowStub.SendMessagesAsync(); } }
public static async Task Main(string[] args) { var settings = new CadenceSettings() { DefaultDomain = "my-domain", CreateDomain = true, Servers = new List <string>() { "cadence://localhost:7933" } }; using (var client = await CadenceClient.ConnectAsync(settings)) { await client.RegisterAssemblyAsync(System.Reflection.Assembly.GetExecutingAssembly()); await client.StartWorkerAsync("my-tasks"); // Invoke the workflow, send it some signals and very that // it changed its state to the signal value. var stub = client.NewWorkflowStub <IMyWorkflow>(); var task = stub.DoItAsync(); await stub.SignalAsync("signal #1"); Console.WriteLine(await stub.GetStatusAsync()); await stub.SignalAsync("signal #2"); Console.WriteLine(await stub.GetStatusAsync()); // This signal completes the workflow. await stub.SignalAsync("done"); await task; } }
public static async Task Main(params string[] args) { var settings = new CadenceSettings() { // This specifies the default domain for operations initiated by the // client connected below (this can be overridden for specific // operations. DefaultDomain = "Acme-PROD", // Host/port for at least one of the Cadence cluster servers: Servers = new List <string>() { "cadence://*****:*****@lilltek.com", "Test subject", "This is a test email."); if (success) { Console.WriteLine("Email SENT!"); } else { Console.WriteLine("Email FAILED!"); } } }
/// <summary> /// Closes the existing Cadence connection and then restarts the Cadence /// server and establishes a new connection. /// </summary> public new void Restart() { // Disconnect. Connection.Dispose(); Connection = null; ConnectionClient.Dispose(); ConnectionClient = null; // Restart the Cadence container. base.Restart(); // Reconnect. Connection = CadenceClient.ConnectAsync(settings).Result; ConnectionClient = new HttpClient() { BaseAddress = Connection.ListenUri }; }
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. using (var client1 = await CadenceClient.ConnectAsync(fixture.Settings)) { await client1.RegisterWorkflowAsync <WorkflowWithResult1>(); await client1.StartWorkerAsync("tasklist-1"); using (var client2 = await CadenceClient.ConnectAsync(fixture.Settings)) { await client2.RegisterWorkflowAsync <WorkflowWithResult2>(); await client2.StartWorkerAsync("tasklist-2"); var options1 = new WorkflowOptions() { TaskList = "tasklist-1" }; var options2 = new WorkflowOptions() { TaskList = "tasklist-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 static async Task Main(string[] args) { // Connect to Cadence var settings = new CadenceSettings() { DefaultDomain = "my-domain", CreateDomain = true, Servers = new List <string>() { "cadence://localhost:7933" } }; using (var client = await CadenceClient.ConnectAsync(settings)) { // Register your workflow implementation to let Cadence // know we're open for business. await client.RegisterWorkflowAsync <HelloWorkflow>(); await client.StartWorkerAsync("my-tasks"); #region code // Invoke a workflow with options: var stub = client.NewWorkflowStub <IHelloWorkflow>( new WorkflowOptions() { WorkflowId = "my-ultimate-workflow", ScheduleToStartTimeout = TimeSpan.FromMinutes(5) }); Console.WriteLine(await stub.HelloAsync("Jeff")); #endregion } }
/// <summary> /// Used to start the fixture within a <see cref="ComposedFixture"/>. /// </summary> /// <param name="settings">Optional Cadence settings.</param> /// <param name="name">Optionally specifies the Cadence container name (defaults to <c>cadence-dev</c>).</param> /// <param name="composeFile"> /// <para> /// Optionally specifies the Temporal Docker compose file text. This defaults to /// <see cref="DefaultComposeFile"/> which configures Temporal server to start with /// a new Cassandra database instance listening on port <b>9042</b> as well as the /// Temporal web UI running on port <b>8088</b>. Temporal server is listening on /// its standard gRPC port <b>7233</b>. /// </para> /// <para> /// You may specify your own Docker compose text file to customize this by configuring /// a different backend database, etc. /// </para> /// </param> /// <param name="defaultDomain">Optionally specifies the default domain for the fixture's client. This defaults to <b>test-domain</b>.</param> /// <param name="logLevel">Specifies the Cadence log level. This defaults to <see cref="Neon.Diagnostics.LogLevel.None"/>.</param> /// <param name="reconnect"> /// Optionally specifies that a new Cadence connection <b>should</b> be established for each /// unit test case. By default, the same connection will be reused which will save about a /// second per test case. /// </param> /// <param name="keepRunning"> /// Optionally indicates that the container should remain running after the fixture is disposed. /// This is handy for using the Temporal web UI for port mortems after tests have completed. /// </param> /// <param name="noClient"> /// Optionally disables establishing a client connection when <c>true</c> /// is passed. The <see cref="Client"/> and <see cref="HttpClient"/> properties /// will be set to <c>null</c> in this case. /// </param> /// <param name="noReset"> /// Optionally prevents the fixture from calling <see cref="CadenceClient.Reset()"/> to /// put the Cadence client library into its initial state before the fixture starts as well /// as when the fixture itself is reset. /// </param> /// <remarks> /// <note> /// A fresh Cadence client <see cref="Client"/> will be established every time this /// fixture is started, regardless of whether the fixture has already been started. This /// ensures that each unit test will start with a client in the default state. /// </note> /// </remarks> public void StartAsComposed( CadenceSettings settings = null, string name = "cadence-dev", string composeFile = DefaultComposeFile, string defaultDomain = DefaultDomain, LogLevel logLevel = LogLevel.None, bool reconnect = false, bool keepRunning = false, bool noClient = false, bool noReset = false) { Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(composeFile), nameof(composeFile)); base.CheckWithinAction(); if (!IsRunning) { // $hack(jefflill): // // The [temporal-dev] Docker test stack may be running from a previous test run. // We need to stop this to avoid network port conflicts. We're just going to // force the removal of the stack's Docker containers. // // This is somewhat fragile because it hardcodes the container names and won't // remove any other stack assets like networks. NeonHelper.ExecuteCapture(NeonHelper.DockerCli, new object[] { "rm", "--force", new string[] { "temporal-dev_cassandra_1", "temporal-dev_temporal-web_1", "temporal-dev_temporal_1" } }); // Reset CadenceClient to its initial state. this.noReset = noReset; if (!noReset) { CadenceClient.Reset(); } // Start the Cadence container. base.StartAsComposed(name, composeFile, keepRunning); // It can take Cadence server some time to start. Rather than relying on [cadence-proxy] // to handle retries (which may take longer than the connect timeout), we're going to wait // up to 4 minutes for Temporal to start listening on its RPC socket. var retry = new LinearRetryPolicy(e => true, maxAttempts: int.MaxValue, retryInterval: TimeSpan.FromSeconds(0.5), timeout: TimeSpan.FromMinutes(4)); retry.Invoke( () => { // The [socket.Connect()] calls below will throw [SocketException] until // Temporal starts listening on its RPC socket. var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); socket.Connect(IPAddress.IPv6Loopback, NetworkPorts.Cadence); socket.Close(); }); Thread.Sleep(TimeSpan.FromSeconds(5)); // Wait a bit longer for luck! // Initialize the settings. settings = settings ?? new CadenceSettings() { CreateDomain = true, DefaultDomain = defaultDomain, LogLevel = logLevel }; if (settings.Servers.Count == 0) { settings.Servers.Add($"http://localhost:{NetworkPorts.Cadence}"); } this.settings = settings; this.reconnect = reconnect; if (!noClient) { // Establish the Cadence connection via the cadence proxy. Client = CadenceClient.ConnectAsync(settings).Result; HttpClient = new HttpClient() { BaseAddress = Client.ListenUri }; } } }
/// <inheritdoc/> protected async override Task <int> OnRunAsync() { // Verify the environment variables. var settings = new CadenceSettings(); var servers = GetEnvironmentVariable("CADENCE_SERVERS"); var domain = GetEnvironmentVariable("CADENCE_DOMAIN"); var taskList = GetEnvironmentVariable("CADENCE_TASKLIST"); var error = false; Log.LogInfo(() => $"CADENCE_SERVERS: {servers}"); Log.LogInfo(() => $"CADENCE_DOMAIN: {domain}"); Log.LogInfo(() => $"CADENCE_TASKLIST: {taskList}"); if (string.IsNullOrEmpty(servers)) { error = true; Log.LogError("The [CADENCE_SERVERS] environment variable is required."); } try { foreach (var item in servers.Split(',')) { var uri = new Uri(item.Trim(), UriKind.Absolute); settings.Servers.Add(uri.ToString()); } } catch { error = true; Log.LogError(() => $"One or more URIs are invalid: CADENCE_SERVERS={servers}"); } if (string.IsNullOrEmpty(domain)) { error = true; Log.LogError("The [CADENCE_DOMAIN] environment variable is required."); } if (string.IsNullOrEmpty(taskList)) { error = true; Log.LogError("The [CADENCE_TASKLIST] environment variable is required."); } if (error) { return(1); } // Connect to Cadence and register the workflows and activities. Log.LogInfo("Connecting to Cadence."); settings.DefaultDomain = domain; using (var client = await CadenceClient.ConnectAsync(settings)) { // Register the workflows. Log.LogInfo("Registering workflows."); await client.RegisterAssemblyAsync(Assembly.GetExecutingAssembly()); // Start the worker. Log.LogInfo("Starting worker."); using (var worker = client.StartWorkerAsync(taskList)) { // Let KubeService know that we're running. Log.LogInfo("Ready for work."); SetRunning(); // Wait for the process terminator to signal that the service is stopping. await Terminator.StopEvent.WaitAsync(); } } return(0); }
public async Task Multiple_TaskLists() { await SyncContext.Clear; // Test the scenario where there multiple clients without // workers that will be used to simulate apps that make calls // on workflows and then create multiple clients that register // different workflows and activities and then verify that // each of the workerless clients are able to execute workflows // and activities and that these end up being executed on the // correct clients. var clients = new List <CadenceClient>(); try { // Initialize the non-worker clients. CadenceClient client1; CadenceClient client2; CadenceClient client3; clients.Add(client1 = await CadenceClient.ConnectAsync(fixture.Settings)); clients.Add(client2 = await CadenceClient.ConnectAsync(fixture.Settings)); clients.Add(client3 = await CadenceClient.ConnectAsync(fixture.Settings)); // Initialize the worker clients. clients.Add(workerClient1 = await CadenceClient.ConnectAsync(fixture.Settings)); clients.Add(workerClient2 = await CadenceClient.ConnectAsync(fixture.Settings)); clients.Add(workerClient3 = await CadenceClient.ConnectAsync(fixture.Settings)); // Start the workers. await workerClient1.RegisterActivityAsync <ActivityWorker1>(); await workerClient1.RegisterWorkflowAsync <WorkflowWorker1>(); await workerClient1.StartWorkerAsync("tasklist-1"); await workerClient2.RegisterActivityAsync <ActivityWorker2>(); await workerClient2.RegisterWorkflowAsync <WorkflowWorker2>(); await workerClient2.StartWorkerAsync("tasklist-2"); await workerClient3.RegisterActivityAsync <ActivityWorker3>(); await workerClient3.RegisterWorkflowAsync <WorkflowWorker3>(); await workerClient3.StartWorkerAsync("tasklist-3"); // Execute each of the worker workflows WITHOUT the associated activities // from each client (both the worker and non-worker clients). foreach (var client in clients) { var stub = client.NewWorkflowStub <IWorkflowWorker1>(); Assert.True(await stub.RunAsync(testActivity: false)); } foreach (var client in clients) { var stub = client.NewWorkflowStub <IWorkflowWorker2>(); Assert.True(await stub.RunAsync(testActivity: false)); } foreach (var client in clients) { var stub = client.NewWorkflowStub <IWorkflowWorker3>(); Assert.True(await stub.RunAsync(testActivity: false)); } // Re-run the workflows calling the activities this time. foreach (var client in clients) { var stub = client.NewWorkflowStub <IWorkflowWorker1>(); Assert.True(await stub.RunAsync(testActivity: true)); } foreach (var client in clients) { var stub = client.NewWorkflowStub <IWorkflowWorker2>(); Assert.True(await stub.RunAsync(testActivity: true)); } foreach (var client in clients) { var stub = client.NewWorkflowStub <IWorkflowWorker3>(); Assert.True(await stub.RunAsync(testActivity: true)); } } finally { foreach (var client in clients) { client.Dispose(); } workerClient1 = null; workerClient2 = null; workerClient3 = null; } }
/// <summary> /// Used to start the fixture within a <see cref="ComposedFixture"/>. /// </summary> /// <param name="settings">Optional Cadence settings.</param> /// <param name="image">Optionally specifies the Cadence container image (defaults to <b>nkubeio/cadence-dev:latest</b>).</param> /// <param name="name">Optionally specifies the Cadence container name (defaults to <c>cb-test</c>).</param> /// <param name="env">Optional environment variables to be passed to the Cadence container, formatted as <b>NAME=VALUE</b> or just <b>NAME</b>.</param> /// <param name="defaultDomain">Optionally specifies the default domain for the fixture's client. This defaults to <b>test-domain</b>.</param> /// <param name="logLevel">Specifies the Cadence log level. This defaults to <see cref="LogLevel.None"/>.</param> /// <param name="keepConnection"> /// Optionally specifies that a new Cadence connection <b>should not</b> be established for each /// unit test case. The same connection will be reused which will save about a second per test. /// </param> /// <param name="keepOpen"> /// Optionally indicates that the container should continue to run after the fixture is disposed. /// </param> /// <param name="hostInterface"> /// Optionally specifies the host interface where the container public ports will be /// published. This defaults to <see cref="ContainerFixture.DefaultHostInterface"/> /// but may be customized. This needs to be an IPv4 address. /// </param> /// <param name="noClient"> /// Optionally disables establishing a client connection when <c>true</c> /// is passed. The <see cref="Client"/> and <see cref="HttpClient"/> properties /// will be set to <c>null</c> in this case. /// </param> /// <param name="noReset"> /// Optionally prevents the fixture from calling <see cref="CadenceClient.Reset()"/> to /// put the Cadence client library into its initial state before the fixture starts as well /// as when the fixture itself is reset. /// </param> /// <param name="emulateProxy"> /// <b>INTERNAL USE ONLY:</b> Optionally starts a partially functional integrated /// <b>cadence-proxy</b> for low-level testing. Most users should never enable this /// because it's probably not going to do what you expect. /// </param> /// <remarks> /// <note> /// A fresh Cadence client <see cref="Client"/> will be established every time this /// fixture is started, regardless of whether the fixture has already been started. This /// ensures that each unit test will start with a client in the default state. /// </note> /// </remarks> public void StartAsComposed( CadenceSettings settings = null, string image = "nkubeio/cadence-dev:latest", string name = "cadence-dev", string[] env = null, string defaultDomain = DefaultDomain, LogLevel logLevel = LogLevel.None, bool keepConnection = false, bool keepOpen = false, string hostInterface = null, bool noClient = false, bool noReset = false, bool emulateProxy = false) { Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(image), nameof(image)); base.CheckWithinAction(); if (!IsRunning) { if (string.IsNullOrEmpty(hostInterface)) { hostInterface = ContainerFixture.DefaultHostInterface; } else { Covenant.Requires <ArgumentException>(IPAddress.TryParse(hostInterface, out var address) && address.AddressFamily == AddressFamily.InterNetwork, nameof(hostInterface), $"[{hostInterface}] is not a valid IPv4 address."); } // Reset CadenceClient to its initial state. this.noReset = noReset; if (!noReset) { CadenceClient.Reset(); } // Start the Cadence container. base.StartAsComposed(name, image, new string[] { "--detach", "-p", $"{GetHostInterface(hostInterface)}:7933-7939:7933-7939", "-p", $"{GetHostInterface(hostInterface)}:8088:8088" }, env: env, keepOpen: keepOpen); Thread.Sleep(warmupDelay); // Initialize the settings. settings = settings ?? new CadenceSettings() { CreateDomain = true, DefaultDomain = defaultDomain, LogLevel = logLevel }; settings.Servers.Clear(); settings.Servers.Add($"http://{GetHostInterface(hostInterface, forConnection: true)}:{NetworkPorts.Cadence}"); this.settings = settings; this.keepConnection = keepConnection; if (!noClient) { // Establish the Cadence connection. Client = CadenceClient.ConnectAsync(settings).Result; HttpClient = new HttpClient() { BaseAddress = Client.ListenUri }; } } }