protected override string OnInit()
        {
            if (Components == null)
            {
                return("ActionTasks not assigned!");
            }

            for (int i = 0; i < Components.Count; i++)
            {
                ActionTaskItem item = Components[i];

                if (!item.Enabled)
                {
                    continue;
                }

                if (item.Task == null)
                {
                    return("Enabled ActionTask not assigned!");
                }

                item.Task.OnInit();
            }

            return(null);
        }
        public IHttpActionResult GetActionTask(string id)
        {
            ActionTaskItem taskItem = ActionQueueManager.Instance.GetTask(id);

            if (taskItem != null)
            {
                return(Ok(taskItem));
            }
            else
            {
                return(BadRequest());
            }
        }
        protected override void OnPause()
        {
            for (int i = 0; i < Components.Count; i++)
            {
                ActionTaskItem item = Components[i];

                if (!item.Enabled)
                {
                    continue;
                }

                item.Task.OnPause();
            }
        }
        public ActionTaskItem GetTask(string taskId)
        {
            ActionTaskItem taskItem = null;

            if (_actionTasks.TryGetValue(taskId, out taskItem))
            {
                Log($"{nameof(this.GetTask)} {taskItem.QueueAction.Action.ConfigName}, id: {taskId}");
            }
            else
            {
                // not a system type error, so log do normal log
                Log($"{nameof(this.GetTask)}, id does not exist: {taskId.ToString()}");
            }

            return(taskItem);
        }
        protected override void OnUpdate()
        {
            for (int i = 0; i < Components.Count; i++)
            {
                ActionTaskItem item = Components[i];

                if (!item.Enabled)
                {
                    continue;
                }

                item.Task.OnUpdate(Time.deltaTime);
                if (IsFinished(item.Task))
                {
                    break;
                }
            }
        }
        void OnExecute()
        {
            for (int i = 0; i < Components.Count; i++)
            {
                ActionTaskItem item = Components[i];

                if (!item.Enabled)
                {
                    continue;
                }

                item.Task.OnExecute();

                if (IsFinished(item.Task))
                {
                    break;
                }
            }
        }
        private void ProcessQueue(CancellationToken cancelToken)
        {
            while (!_actionQueue.IsCompleted && !cancelToken.IsCancellationRequested)
            {
                ActionQueueItem queueItem = null;
                // Blocks if number.Count == 0
                // IOE means that Take() was called on a completed collection.
                // Some other thread can call CompleteAdding after we pass the
                // IsCompleted check but before we call Take.
                // In this example, we can simply catch the exception since the
                // loop will break on the next iteration.
                try
                {
                    queueItem = _actionQueue.Take();
                }
                catch (InvalidOperationException)
                {
                    // when we shut down, we expect this exception is the queue is complete; but
                    // if not complete...
                    if (!_actionQueue.IsCompleted)
                    {
                        throw;
                    }
                }

                if (queueItem != null)
                {
                    bool doThreaded = _actionThreading && !string.IsNullOrWhiteSpace(queueItem.Action.TaskId);
                    if (doThreaded)
                    {
                        try
                        {
                            // create a task item without a real task at this point; we'll set it once we know
                            // we can add it successfully (and no dups)
                            ActionTaskItem taskItem = new ActionTaskItem(queueItem, null, new CancellationTokenSource());
                            if (!_actionTasks.TryAdd(queueItem.Action.TaskId, taskItem))
                            {
                                Error($"Duplicate threadId found; ignoring action.  ID: {queueItem.Action.TaskId.ToString()}");
                                continue;
                            }
                            else
                            {
                                Log($"Adding thread id: {queueItem.Action.TaskId.ToString()}");
                            }

                            // run the task, saving "t" as this task; if we did Run and Continue in one statement,
                            // the returned task would be the Continue task and would be waiting
                            Task t = Task.Run(() => Process(queueItem, taskItem.CancellationTokenSource));
                            t.ContinueWith(task =>
                            {
                                if (task.IsFaulted)
                                {
                                    Error(task.Exception.ToString());
                                }

                                ActionTaskItem tempTaskItem;
                                if (!_actionTasks.TryRemove(queueItem.Action.TaskId, out tempTaskItem))
                                {
                                    Error($"Unable to remove action thread by thread id: {queueItem.Action.TaskId.ToString()}");
                                }
                                else
                                {
                                    Log($"Removing thread id: {queueItem.Action.TaskId.ToString()}");
                                }
                            });

                            // not that the task is running, set the task item Task
                            taskItem.Task = t;
                        }
                        finally
                        {
                        }
                    }
                    else
                    {
                        Process(queueItem, cancelSource: null);
                    }
                }
            }
        }