Esempio n. 1
0
        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();
            }
        }
Esempio n. 2
0
        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");
            }
        }
Esempio n. 3
0
        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"));
                }
            }
        }
Esempio n. 4
0
        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");
            }
        }
Esempio n. 5
0
        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"));
            }
        }
Esempio n. 6
0
        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"));
            }
        }
Esempio n. 7
0
        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");
            }
        }
Esempio n. 8
0
        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"));
            }
        }
Esempio n. 9
0
        /// <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
            };
        }
Esempio n. 10
0
        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;
            }
        }
Esempio n. 11
0
        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;
            }
        }
Esempio n. 12
0
        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();
            }
        }
Esempio n. 13
0
        /// <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
                };
            }
        }
Esempio n. 14
0
        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
        }
Esempio n. 15
0
        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");
            }
        }
Esempio n. 16
0
        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();
            }
        }
Esempio n. 17
0
        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;
            }
        }
Esempio n. 18
0
        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!");
                }
            }
        }
Esempio n. 19
0
        /// <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
            };
        }
Esempio n. 20
0
        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"));
                }
            }
        }
Esempio n. 21
0
        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
            }
        }
Esempio n. 22
0
        /// <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
                    };
                }
            }
        }
Esempio n. 23
0
        /// <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);
        }
Esempio n. 24
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;
            }
        }
Esempio n. 25
0
        /// <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
                    };
                }
            }
        }