Example #1
0
 void cancel(Order order)
 {
     if (order != null)
     {
         //TODO enqueue order
         order = null;
         mode  = WorkerMode.Idle;
     }
 }
Example #2
0
 /// <summary>
 /// Internal constructor.
 /// </summary>
 /// <param name="client">The parent client.</param>
 /// <param name="mode">Identifies whether the worker will process activities, workflows, or both.</param>
 /// <param name="workerId">The ID of the worker as tracked by the <b>cadence-proxy</b>.</param>
 /// <param name="domain">The Cadence domain where the worker is registered.</param>
 /// <param name="taskList">The Cadence task list.</param>
 internal Worker(CadenceClient client, WorkerMode mode, long workerId, string domain, string taskList)
 {
     this.Client   = client;
     this.Mode     = mode;
     this.WorkerId = workerId;
     this.Domain   = domain;
     this.Tasklist = taskList;
     this.RefCount = 1;
 }
Example #3
0
        public void SetWorkerMode(WorkerMode mode)
        {
            var comboBoxPtr = this.GetChildWindow(1, "ComboBox");

            if (comboBoxPtr == IntPtr.Zero)
            {
                this.OnWorkerErrorOccurred("An incompatible worker is running");
                return;
            }

            WinAPIUtils.SetComboBoxSelectedIndex(comboBoxPtr, GetExternalWorkerModeIndex(mode));
        }
Example #4
0
        private int GetExternalWorkerModeIndex(WorkerMode mode)
        {
            switch (mode)
            {
            case WorkerMode.Disabled: return(0);

            case WorkerMode.WorkWhenIdle: return(1);

            case WorkerMode.WorkProportional: return(3);

            case WorkerMode.WorkAlways: return(2);

            default:
                Debug.Assert(false, "Unsupported worker mode");
                return(0);
            }
        }
Example #5
0
        /// <summary>
        /// Signals Cadence that the application is capable of executing workflows and/or activities for a specific
        /// domain and task list.
        /// </summary>
        /// <param name="taskList">Specifies the task list implemented by the worker.  This must not be empty.</param>
        /// <param name="options">Optionally specifies additional worker options.</param>
        /// <param name="domain">Optionally overrides the default <see cref="CadenceClient"/> domain.</param>
        /// <returns>A <see cref="Worker"/> identifying the worker instance.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="taskList"/> is <c>null</c> or empty.</exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown when an attempt is made to recreate a worker with the
        /// same properties on a given client.  See the note in the remarks.
        /// </exception>
        /// <remarks>
        /// <note>
        /// <see cref="CadenceClient"/> for more information on task lists.
        /// </note>
        /// <para>
        /// Your workflow application will need to call this method so that Cadence will know
        /// that it can schedule activities to run within the current process.  You'll need
        /// to specify the target Cadence domain and task list.
        /// </para>
        /// <para>
        /// You may also specify an optional <see cref="WorkerOptions"/> parameter as well
        /// as customize the name used to register the activity, which defaults to the
        /// fully qualified name of the activity type.
        /// </para>
        /// <para>
        /// This method returns a <see cref="Worker"/> which implements <see cref="IDisposable"/>.
        /// It's a best practice to call <see cref="Dispose()"/> just before the a worker process
        /// terminates, but this is optional.  Advanced worker implementation that need to change
        /// their configuration over time can also call <see cref="Dispose()"/> to stop workers
        /// for specific domains and task lists.
        /// </para>
        /// <note>
        /// The Cadence GOLANG client does not appear to support starting a worker with a given
        /// set of parameters, stopping that workflow, and then restarting another worker
        /// with the same parameters on the same client.  This method detects this situation
        /// and throws an <see cref="InvalidOperationException"/> when a restart is attempted.
        /// </note>
        /// </remarks>
        public async Task <Worker> StartWorkerAsync(string taskList, WorkerOptions options = null, string domain = null)
        {
            await SyncContext.ClearAsync;

            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(taskList), nameof(taskList), "Workers must be started with a non-empty workflow.");
            EnsureNotDisposed();

            options = options ?? new WorkerOptions();
            domain  = ResolveDomain(domain);

            WorkerMode mode = options.Mode;
            Worker     worker;

            try
            {
                using (await workerRegistrationMutex.AcquireAsync())
                {
                    // Ensure that we haven't already registered a worker for the
                    // specified activity, domain, and task list.  We'll just increment
                    // the reference count for the existing worker and return it
                    // in this case.
                    //
                    // I know that this is a linear search but the number of activity
                    // registrations per service will generally be very small and
                    // registrations will happen infrequently (typically just once
                    // per service, when it starts).

                    // $note(jefflill):
                    //
                    // If the worker exists but its RefCount==0, then we're going to
                    // throw an exception because Cadence doesn't support recreating
                    // a worker with the same parameters on the same client.

                    worker = workers.Values.SingleOrDefault(wf => wf.Mode == mode && wf.Domain == domain && wf.Tasklist == taskList);

                    if (worker != null)
                    {
                        if (worker.RefCount < 0)
                        {
                            throw new InvalidOperationException("A worker with these same parameters has already been started and stopped on this Cadence client.  Cadence does not support recreating workers for a given client instance.");
                        }

                        Interlocked.Increment(ref worker.RefCount);
                        return(worker);
                    }

                    options = options ?? new WorkerOptions();

                    var reply = (NewWorkerReply)(await CallProxyAsync(
                                                     new NewWorkerRequest()
                    {
                        Domain = ResolveDomain(domain),
                        TaskList = taskList,
                        Options = options.ToInternal()
                    }));

                    reply.ThrowOnError();

                    worker = new Worker(this, mode, reply.WorkerId, domain, taskList);
                    workers.Add(reply.WorkerId, worker);
                }
            }
            finally
            {
                switch (mode)
                {
                case WorkerMode.Activity:

                    activityWorkerStarted = true;
                    break;

                case WorkerMode.Workflow:

                    workflowWorkerStarted = true;
                    break;

                case WorkerMode.Both:

                    activityWorkerStarted = true;
                    workflowWorkerStarted = true;
                    break;

                default:

                    throw new NotImplementedException();
                }
            }

            // Fetch the stub for each registered workflow and activity type so that
            // they'll be precompiled so compilation won't impact workflow and activity
            // performance including potentially intruducing enough delay to cause
            // decision tasks or activity heartbeats to fail (in very rare situations).
            //
            // Note that the compiled stubs are cached, so we don't need to worry
            // about compiling stubs for types more than once causing a problem.

            lock (registeredWorkflowTypes)
            {
                foreach (var workflowInterface in registeredWorkflowTypes)
                {
                    // Workflows, we're going to compile both the external and child
                    // versions of the stubs.

                    StubManager.GetWorkflowStub(workflowInterface, isChild: false);
                    StubManager.GetWorkflowStub(workflowInterface, isChild: true);
                }
            }

            lock (registeredActivityTypes)
            {
                foreach (var activityInterface in registeredActivityTypes)
                {
                    StubManager.GetActivityStub(activityInterface);
                }
            }

            return(worker);
        }
Example #6
0
 private void SettingsPage_WorkerModeChanged(object sender, WorkerMode mode)
 {
     UpdateTrayIcon();
 }
Example #7
0
    public void handle()
    {
        if (mode == WorkerMode.GoToProducer)
        {
            //TODO moveTo();
            mode = WorkerMode.GoingToProducer;
        }
        if (mode == WorkerMode.GoingToProducer)
        {
            move();
            if (next == null)
            {
                mode = WorkerMode = OrderRessources;
            }
        }
        else if (mode == WorkerMode.OrderRessources)
        {
            //TODO
            mode = WorkerMode.WaitForRessources;
        }
        else if (mode == WorkerMode.WaitForRessources)
        {
            //TODO
        }
        else if (mode == WorkerMode.ProduceProduct)
        {
            long productionReady = DateTime.Now.Ticks/TimeSpan.TicksPerMillisecond + order.recipe.time*order.number;
            mode = WorkerMode.ProducingProduct;
        }
        else if (mode == WorkerMode.ProducingProduct)
        {
            if (DateTime.Now.Ticks/TimeSpan.TicksPerMillisecond >= productionReady)
            {
                mode = WorkerMode.LoadProducts;
            }
        }
        else if (mode == WorkerMode.ImproveProducts)
        {
            //TODO
        }
        else if (mode == WorkerMode.ImproveingProducts)
        {
            //TODO
        }
        else if (mode == WorkerMode.LoadProducts)
        {
            //TODO
            mode = WorkerMode.DeliverProducts;
        }
        else if (mode == WorkerMode.DeliverProducts)
        {
            //TODO moveTo();
            mode = WorkerMode.DeliveringProducts;
        }
        else if (mode == WorkerMode.DeliveringProducts)
        {
            move();
            if (next == null)
            {
                mode = WorkerMode.UnloadProducts;
            }
        }
        else if (mode == WorkerMode.UnloadProducts)
        {
            //TODO
            mode = WorkerMode.Idle;
            order = null;
            priority = Priority.Idle;
            //TODO dequeue
            //TODO enqueue
        }
        else if (mode == WorkerMode.Build)
        {

        }
        else if (mode == WorkerMode.Idle)
        {

        }
    }
Example #8
0
 void cancel(Order order)
 {
     if (order != null)
     {
         //TODO enqueue order
         order = null;
         mode = WorkerMode.Idle;
     }
 }
Example #9
0
 private void WorkerPage_WorkerModeChanged(object sender, WorkerMode mode)
 {
     ChangeWorkerMode((int)mode);
 }
Example #10
0
 public void handle()
 {
     if (mode == WorkerMode.GoToProducer)
     {
         //TODO moveTo();
         mode = WorkerMode.GoingToProducer;
     }
     if (mode == WorkerMode.GoingToProducer)
     {
         move();
         if (next == null)
         {
             mode = WorkerMode = OrderRessources;
         }
     }
     else if (mode == WorkerMode.OrderRessources)
     {
         //TODO
         mode = WorkerMode.WaitForRessources;
     }
     else if (mode == WorkerMode.WaitForRessources)
     {
         //TODO
     }
     else if (mode == WorkerMode.ProduceProduct)
     {
         long productionReady = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond + order.recipe.time * order.number;
         mode = WorkerMode.ProducingProduct;
     }
     else if (mode == WorkerMode.ProducingProduct)
     {
         if (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond >= productionReady)
         {
             mode = WorkerMode.LoadProducts;
         }
     }
     else if (mode == WorkerMode.ImproveProducts)
     {
         //TODO
     }
     else if (mode == WorkerMode.ImproveingProducts)
     {
         //TODO
     }
     else if (mode == WorkerMode.LoadProducts)
     {
         //TODO
         mode = WorkerMode.DeliverProducts;
     }
     else if (mode == WorkerMode.DeliverProducts)
     {
         //TODO moveTo();
         mode = WorkerMode.DeliveringProducts;
     }
     else if (mode == WorkerMode.DeliveringProducts)
     {
         move();
         if (next == null)
         {
             mode = WorkerMode.UnloadProducts;
         }
     }
     else if (mode == WorkerMode.UnloadProducts)
     {
         //TODO
         mode     = WorkerMode.Idle;
         order    = null;
         priority = Priority.Idle;
         //TODO dequeue
         //TODO enqueue
     }
     else if (mode == WorkerMode.Build)
     {
     }
     else if (mode == WorkerMode.Idle)
     {
     }
 }
Example #11
0
        /// <summary>
        /// Signals Cadence that the application is capable of executing activities for a specific
        /// domain and task list.
        /// </summary>
        /// <param name="taskList">Optionally specifies the target task list (defaults to <b>"default"</b>).</param>
        /// <param name="options">Optionally specifies additional worker options.</param>
        /// <param name="domain">Optionally overrides the default <see cref="CadenceClient"/> domain.</param>
        /// <returns>A <see cref="Worker"/> identifying the worker instance.</returns>
        /// <exception cref="InvalidOperationException">
        /// Thrown when an attempt is made to recreate a worker with the
        /// same properties on a given client.  See the note in the remarks.
        /// </exception>
        /// <remarks>
        /// <para>
        /// Your workflow application will need to call this method so that Cadence will know
        /// that it can schedule activities to run within the current process.  You'll need
        /// to specify the target Cadence domain and task list.
        /// </para>
        /// <para>
        /// You may also specify an optional <see cref="WorkerOptions"/> parameter as well
        /// as customize the name used to register the activity, which defaults to the
        /// fully qualified name of the activity type.
        /// </para>
        /// <para>
        /// This method returns a <see cref="Worker"/> which implements <see cref="IDisposable"/>.
        /// It's a best practice to call <see cref="Dispose()"/> just before the a worker process
        /// terminates, but this is optional.  Advanced worker implementation that need to change
        /// their configuration over time can also call <see cref="Dispose()"/> to stop workers
        /// for specific domains and task lists.
        /// </para>
        /// <note>
        /// The Cadence GOLANG client does not appear to support starting a worker with a given
        /// set of parameters, stopping that workflow, and then restarting another worker
        /// with the same parameters on the same client.  This method detects this situation
        /// and throws an <see cref="InvalidOperationException"/> when these restart attempts
        /// are made.
        /// </note>
        /// </remarks>
        private async Task <Worker> StartWorkerAsync(string taskList = "default", WorkerOptions options = null, string domain = null)
        {
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(taskList));

            options = options ?? new WorkerOptions();

            WorkerMode mode = options.Mode;
            Worker     worker;

            try
            {
                using (await workerRegistrationMutex.AcquireAsync())
                {
                    // Ensure that we haven't already registered a worker for the
                    // specified activity, domain, and task list.  We'll just increment
                    // the reference count for the existing worker and return it
                    // in this case.
                    //
                    // I know that this is a linear search but the number of activity
                    // registrations per service will generally be very small and
                    // registrations will happen infrequently (typically just once
                    // per service, when it starts).

                    // $note(jeff.lill):
                    //
                    // If the worker exists but its refcount==0, then we're going to
                    // throw an exception because Cadence doesn't support recreating
                    // a worker with the same parameters on the same client.

                    worker = workers.Values.SingleOrDefault(wf => wf.Mode == mode && wf.Domain == domain && wf.Tasklist == taskList);

                    if (worker != null)
                    {
                        if (worker.RefCount == 0)
                        {
                            throw new InvalidOperationException("A worker with these same parameters has already been started and stopped on this Cadence client.  Cadence does not support recreating workers for a given client instance.");
                        }

                        Interlocked.Increment(ref worker.RefCount);
                        return(worker);
                    }

                    options = options ?? new WorkerOptions();

                    var reply = (NewWorkerReply)(await CallProxyAsync(
                                                     new NewWorkerRequest()
                    {
                        Domain = ResolveDomain(domain),
                        TaskList = taskList,
                        Options = options.ToInternal()
                    }));

                    reply.ThrowOnError();

                    worker = new Worker(this, mode, reply.WorkerId, domain, taskList);
                    workers.Add(reply.WorkerId, worker);
                }
            }
            finally
            {
                switch (mode)
                {
                case WorkerMode.Activity:

                    activityWorkerStarted = true;
                    break;

                case WorkerMode.Workflow:

                    workflowWorkerStarted = true;
                    break;

                case WorkerMode.Both:

                    activityWorkerStarted = true;
                    workflowWorkerStarted = true;
                    break;

                default:

                    throw new NotImplementedException();
                }
            }

            return(worker);
        }