예제 #1
0
        public async Task <string> StartWorkflow <TData>(string workflowId, int?version, TData data = null)
            where TData : class
        {
            var def = _registry.GetDefinition(workflowId, version);

            if (def == null)
            {
                throw new WorkflowNotRegisteredException(workflowId, version);
            }

            var wf = new WorkflowInstance
            {
                WorkflowDefinitionId = workflowId,
                Version       = def.Version,
                Data          = data,
                Description   = def.Description,
                NextExecution = 0,
                CreateTime    = DateTime.Now.ToUniversalTime(),
                Status        = WorkflowStatus.Runnable
            };

            if ((def.DataType != null) && (data == null))
            {
                wf.Data = TypeExtensions.GetConstructor(def.DataType, new Type[] { }).Invoke(null);
            }

            wf.ExecutionPointers.Add(_pointerFactory.BuildGenesisPointer(def));

            string id = await _persistenceStore.CreateNewWorkflow(wf);

            await _queueProvider.QueueWork(id, QueueType.Workflow);

            return(id);
        }
예제 #2
0
        /// <summary>
        /// Poll the persistence store for workflows ready to run.
        /// Poll the persistence store for stashed unpublished events
        /// </summary>
        private async void PollRunnables(object target)
        {
            try
            {
                if (await _lockProvider.AcquireLock("poll runnables", new CancellationToken()))
                {
                    try
                    {
                        _logger.LogInformation("Polling for runnable workflows");
                        var runnables = await _persistenceStore.GetRunnableInstances(DateTime.Now);

                        foreach (var item in runnables)
                        {
                            _logger.LogDebug("Got runnable instance {0}", item);
                            await _queueProvider.QueueWork(item, QueueType.Workflow);
                        }
                    }
                    finally
                    {
                        await _lockProvider.ReleaseLock("poll runnables");
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
            }

            try
            {
                if (await _lockProvider.AcquireLock("unprocessed events", new CancellationToken()))
                {
                    try
                    {
                        _logger.LogInformation("Polling for unprocessed events");
                        var events = await _persistenceStore.GetRunnableEvents(DateTime.Now);

                        foreach (var item in events.ToList())
                        {
                            _logger.LogDebug($"Got unprocessed event {item}");
                            await _queueProvider.QueueWork(item, QueueType.Event);
                        }
                    }
                    finally
                    {
                        await _lockProvider.ReleaseLock("unprocessed events");
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
            }
        }
예제 #3
0
        public async Task <string> StartWorkflow <TData>(string workflowId, int?version, TData data = null, string reference = null)
            where TData : class, new()
        {
            var def = _registry.GetDefinition(workflowId, version);

            if (def == null)
            {
                throw new WorkflowNotRegisteredException(workflowId, version);
            }

            var wf = new WorkflowInstance
            {
                WorkflowDefinitionId = workflowId,
                Version       = def.Version,
                Data          = data,
                Description   = def.Description,
                NextExecution = 0,
                CreateTime    = DateTime.Now.ToUniversalTime(),
                Status        = WorkflowStatus.Runnable,
                Reference     = reference
            };

            if ((def.DataType != null) && (data == null))
            {
                if (typeof(TData) == def.DataType)
                {
                    wf.Data = new TData();
                }
                else
                {
                    wf.Data = def.DataType.GetConstructor(new Type[0]).Invoke(new object[0]);
                }
            }

            wf.ExecutionPointers.Add(_pointerFactory.BuildGenesisPointer(def));

            string id = await _persistenceStore.CreateNewWorkflow(wf);

            await _queueProvider.QueueWork(id, QueueType.Workflow);

            await _searchIndex.IndexWorkflow(wf);

            await _eventHub.PublishNotification(new WorkflowStarted()
            {
                EventTimeUtc         = DateTime.UtcNow,
                Reference            = reference,
                WorkflowInstanceId   = id,
                WorkflowDefinitionId = def.Id,
                Version = def.Version
            });

            return(id);
        }
예제 #4
0
        private async Task PollWorkflows()
        {
            try
            {
                if (await _lockProvider.AcquireLock("poll runnables", new CancellationToken()))
                {
                    try
                    {
                        _logger.LogDebug("Polling for runnable workflows");

                        var runnables = await _persistenceStore.GetRunnableInstances(_dateTimeProvider.Now);

                        foreach (var item in runnables)
                        {
                            if (_persistenceStore.SupportsScheduledCommands)
                            {
                                try
                                {
                                    await _persistenceStore.ScheduleCommand(new ScheduledCommand()
                                    {
                                        CommandName = ScheduledCommand.ProcessWorkflow,
                                        Data        = item,
                                        ExecuteTime = _dateTimeProvider.UtcNow.Ticks
                                    });

                                    continue;
                                }
                                catch (Exception ex)
                                {
                                    _logger.LogError(ex, ex.Message);
                                }
                            }
                            if (_greylist.Contains($"wf:{item}"))
                            {
                                _logger.LogDebug($"Got greylisted workflow {item}");
                                continue;
                            }
                            _logger.LogDebug("Got runnable instance {0}", item);
                            _greylist.Add($"wf:{item}");
                            await _queueProvider.QueueWork(item, QueueType.Workflow);
                        }
                    }
                    finally
                    {
                        await _lockProvider.ReleaseLock("poll runnables");
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
            }
        }
예제 #5
0
        private async Task Execute()
        {
            try
            {
                var cancelToken = _cancellationTokenSource.Token;
                var opts        = new ExecutionDataflowBlockOptions()
                {
                    MaxDegreeOfParallelism = MaxConcurrentItems,
                    BoundedCapacity        = MaxConcurrentItems + 1
                };

                var actionBlock = new ActionBlock <string>(ExecuteItem, opts);

                while (!cancelToken.IsCancellationRequested)
                {
                    try
                    {
                        if (!SpinWait.SpinUntil(() => actionBlock.InputCount == 0, Options.IdleTime))
                        {
                            continue;
                        }

                        var item = await QueueProvider.DequeueWork(Queue, cancelToken);

                        if (item == null)
                        {
                            if (!QueueProvider.IsDequeueBlocking)
                            {
                                await Task.Delay(Options.IdleTime, cancelToken);
                            }
                            continue;
                        }

                        if (!actionBlock.Post(item))
                        {
                            await QueueProvider.QueueWork(item, Queue);
                        }
                    }
                    catch (OperationCanceledException ce)
                    {
                        Logger.LogError(ce.Message, ce);
                    }
                    catch (Exception ex)
                    {
                        Logger.LogError(ex.Message, ex);
                    }
                }

                actionBlock.Complete();
                await actionBlock.Completion;
            }
            catch (Exception ex)
            {
                Logger.LogError(ex.Message, ex);
                //This is to prevent async void crashing the program.
                //Should never reach this line
                //TODO remove async void
            }
        }
예제 #6
0
        public async Task <string> StartWorkflow <TData>(string workflowId, int?version, TData data = null)
            where TData : class
        {
            var def = _registry.GetDefinition(workflowId, version);

            if (def == null)
            {
                throw new WorkflowNotRegisteredException(workflowId, version);
            }

            var wf = new WorkflowInstance
            {
                WorkflowDefinitionId = workflowId,
                Version       = def.Version,
                Data          = data,
                Description   = def.Description,
                NextExecution = 0,
                CreateTime    = DateTime.Now.ToUniversalTime(),
                Status        = WorkflowStatus.Runnable
            };

            if ((def.DataType != null) && (data == null))
            {
                wf.Data = TypeExtensions.GetConstructor(def.DataType, new Type[] { }).Invoke(null);
            }

            wf.ExecutionPointers.Add(new ExecutionPointer
            {
                Id       = Guid.NewGuid().ToString(),
                StepId   = 0,
                Active   = true,
                StepName = Enumerable.First <WorkflowStep>(def.Steps, x => x.Id == 0).Name
            });

            string id = await _persistenceStore.CreateNewWorkflow(wf);

            await _queueProvider.QueueWork(id, QueueType.Workflow);

            return(id);
        }
예제 #7
0
        private async Task <bool> SeedSubscription(Event evt, EventSubscription sub)
        {
            if (await _lockProvider.AcquireLock(sub.WorkflowId))
            {
                try
                {
                    var workflow = await _persistenceStore.GetWorkflowInstance(sub.WorkflowId);

                    var pointers = workflow.ExecutionPointers.Where(p => p.EventName == sub.EventName && p.EventKey == sub.EventKey && !p.EventPublished);
                    foreach (var p in pointers)
                    {
                        p.EventData      = evt.EventData;
                        p.EventPublished = true;
                        p.Active         = true;
                    }
                    workflow.NextExecution = 0;
                    await _persistenceStore.PersistWorkflow(workflow);

                    await _persistenceStore.TerminateSubscription(sub.Id);

                    return(true);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex.Message);
                    return(false);
                }
                finally
                {
                    await _lockProvider.ReleaseLock(sub.WorkflowId);

                    await _queueProvider.QueueWork(sub.WorkflowId, QueueType.Workflow);
                }
            }
            else
            {
                _logger.LogInformation("Workflow locked {0}", sub.WorkflowId);
                return(false);
            }
        }
        public async Task <WorkflowInstance> RunWorkflowSync <TData>(string workflowId, int version, TData data, string reference, CancellationToken token, bool persistSate = true)
            where TData : new()
        {
            var def = _registry.GetDefinition(workflowId, version);

            if (def == null)
            {
                throw new WorkflowNotRegisteredException(workflowId, version);
            }

            var wf = new WorkflowInstance
            {
                WorkflowDefinitionId = workflowId,
                Version       = def.Version,
                Data          = data,
                Description   = def.Description,
                NextExecution = 0,
                CreateTime    = _dateTimeProvider.UtcNow,
                Status        = WorkflowStatus.Suspended,
                Reference     = reference
            };

            if ((def.DataType != null) && (data == null))
            {
                if (typeof(TData) == def.DataType)
                {
                    wf.Data = new TData();
                }
                else
                {
                    wf.Data = def.DataType.GetConstructor(new Type[0]).Invoke(new object[0]);
                }
            }

            wf.ExecutionPointers.Add(_pointerFactory.BuildGenesisPointer(def));

            var id = Guid.NewGuid().ToString();

            if (persistSate)
            {
                id = await _persistenceStore.CreateNewWorkflow(wf, token);
            }
            else
            {
                wf.Id = id;
            }

            wf.Status = WorkflowStatus.Runnable;

            if (!await _lockService.AcquireLock(id, CancellationToken.None))
            {
                throw new InvalidOperationException();
            }

            try
            {
                while ((wf.Status == WorkflowStatus.Runnable) && !token.IsCancellationRequested)
                {
                    await _executor.Execute(wf, token);

                    if (persistSate)
                    {
                        await _persistenceStore.PersistWorkflow(wf, token);
                    }
                }
            }
            finally
            {
                await _lockService.ReleaseLock(id);
            }

            if (persistSate)
            {
                await _queueService.QueueWork(id, QueueType.Index);
            }

            return(wf);
        }
예제 #9
0
        private async void Execute()
        {
            var cancelToken  = _cancellationTokenSource.Token;
            var activeTasks  = new Dictionary <string, Task>();
            var secondPasses = new HashSet <string>();

            while (!cancelToken.IsCancellationRequested)
            {
                try
                {
                    if (activeTasks.Count >= MaxConcurrentItems)
                    {
                        await Task.Delay(Options.IdleTime);

                        continue;
                    }

                    var item = await QueueProvider.DequeueWork(Queue, cancelToken);

                    if (item == null)
                    {
                        if (!QueueProvider.IsDequeueBlocking)
                        {
                            await Task.Delay(Options.IdleTime, cancelToken);
                        }
                        continue;
                    }

                    if (activeTasks.ContainsKey(item))
                    {
                        secondPasses.Add(item);
                        if (!EnableSecondPasses)
                        {
                            await QueueProvider.QueueWork(item, Queue);
                        }
                        continue;
                    }

                    secondPasses.Remove(item);

                    var task = new Task(async(object data) =>
                    {
                        try
                        {
                            await ExecuteItem((string)data);
                            while (EnableSecondPasses && secondPasses.Contains(item))
                            {
                                secondPasses.Remove(item);
                                await ExecuteItem((string)data);
                            }
                        }
                        finally
                        {
                            lock (activeTasks)
                            {
                                activeTasks.Remove((string)data);
                            }
                        }
                    }, item);
                    lock (activeTasks)
                    {
                        activeTasks.Add(item, task);
                    }

                    task.Start();
                }
                catch (OperationCanceledException)
                {
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex, ex.Message);
                }
            }

            foreach (var task in activeTasks.Values)
            {
                task.Wait();
            }
        }
예제 #10
0
        private async Task Execute()
        {
            var cancelToken = _cancellationTokenSource.Token;

            while (!cancelToken.IsCancellationRequested)
            {
                try
                {
                    var activeCount = 0;
                    lock (_activeTasks)
                    {
                        activeCount = _activeTasks.Count;
                    }
                    if (activeCount >= MaxConcurrentItems)
                    {
                        await Task.Delay(Options.IdleTime);

                        continue;
                    }

                    var item = await QueueProvider.DequeueWork(Queue, cancelToken);

                    if (item == null)
                    {
                        if (!QueueProvider.IsDequeueBlocking)
                        {
                            await Task.Delay(Options.IdleTime, cancelToken);
                        }
                        continue;
                    }

                    var hasTask = false;
                    lock (_activeTasks)
                    {
                        hasTask = _activeTasks.ContainsKey(item);
                    }
                    if (hasTask)
                    {
                        _secondPasses.Add(item);
                        if (!EnableSecondPasses)
                        {
                            await QueueProvider.QueueWork(item, Queue);
                        }
                        continue;
                    }

                    _secondPasses.TryRemove(item);

                    var waitHandle = new ManualResetEvent(false);
                    lock (_activeTasks)
                    {
                        _activeTasks.Add(item, waitHandle);
                    }
                    var task = ExecuteItem(item, waitHandle);
                }
                catch (OperationCanceledException)
                {
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex, ex.Message);
                }
            }

            List <EventWaitHandle> toComplete;

            lock (_activeTasks)
            {
                toComplete = _activeTasks.Values.ToList();
            }

            foreach (var handle in toComplete)
            {
                handle.WaitOne();
            }
        }
예제 #11
0
        /// <summary>
        /// Poll the persistence store for workflows ready to run.
        /// Poll the persistence store for stashed unpublished events
        /// </summary>
        private async void PollRunnables(object target)
        {
            try
            {
                if (await _lockProvider.AcquireLock("poll runnables", new CancellationToken()))
                {
                    try
                    {
                        _logger.LogInformation("Polling for runnable workflows");
                        var runnables = (await _persistenceStore.GetRunnableInstances(DateTime.Now)).ToArray();
                        _logger.LogInformation($"Polled {runnables.Length} runnable workflows");
                        foreach (var item in runnables)
                        {
                            if (_greylist.Contains($"wf:{item}"))
                            {
                                _logger.LogDebug($"Got greylisted workflow {item}");
                                continue;
                            }
                            _logger.LogDebug("Got runnable instance {0}", item);
                            _greylist.Add($"wf:{item}");
                            await _queueProvider.QueueWork(item, QueueType.Workflow);
                        }
                    }
                    finally
                    {
                        await _lockProvider.ReleaseLock("poll runnables");
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
            }

            try
            {
                if (await _lockProvider.AcquireLock("unprocessed events", new CancellationToken()))
                {
                    try
                    {
                        _logger.LogInformation("Polling for unprocessed events");
                        var events = (await _persistenceStore.GetRunnableEvents(DateTime.Now)).ToArray();
                        _logger.LogInformation($"Polled {events.Length} unprocessed events");
                        foreach (var item in events)
                        {
                            if (_greylist.Contains($"evt:{item}"))
                            {
                                _logger.LogDebug($"Got greylisted event {item}");
                                _greylist.Add($"evt:{item}");
                                continue;
                            }
                            _logger.LogDebug($"Got unprocessed event {item}");
                            _greylist.Add($"evt:{item}");
                            await _queueProvider.QueueWork(item, QueueType.Event);
                        }
                    }
                    finally
                    {
                        await _lockProvider.ReleaseLock("unprocessed events");
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
            }
        }
예제 #12
0
        /// <summary>
        /// Worker thread body
        /// </summary>
        private async void RunWorkflows()
        {
            while (!_shutdown)
            {
                try
                {
                    var workflowId = await _queueProvider.DequeueWork(QueueType.Workflow);

                    if (workflowId != null)
                    {
                        try
                        {
                            if (await _lockProvider.AcquireLock(workflowId))
                            {
                                WorkflowInstance       workflow = null;
                                WorkflowExecutorResult result   = null;
                                try
                                {
                                    workflow = await _persistenceStore.GetWorkflowInstance(workflowId);

                                    if (workflow.Status == WorkflowStatus.Runnable)
                                    {
                                        try
                                        {
                                            result = _executor.Execute(workflow, _options);
                                        }
                                        finally
                                        {
                                            await _persistenceStore.PersistWorkflow(workflow);
                                        }
                                    }
                                }
                                finally
                                {
                                    await _lockProvider.ReleaseLock(workflowId);

                                    if ((workflow != null) && (result != null))
                                    {
                                        foreach (var sub in result.Subscriptions)
                                        {
                                            await SubscribeEvent(sub);
                                        }

                                        await _persistenceStore.PersistErrors(result.Errors);

                                        if ((workflow.Status == WorkflowStatus.Runnable) && workflow.NextExecution.HasValue && workflow.NextExecution.Value < DateTime.Now.ToUniversalTime().Ticks)
                                        {
                                            await _queueProvider.QueueWork(workflowId, QueueType.Workflow);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                _logger.LogInformation("Workflow locked {0}", workflowId);
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex.Message);
                        }
                    }
                    else
                    {
                        await Task.Delay(_options.IdleTime);  //no work
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex.Message);
                }
            }
        }