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); }
/// <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); } }
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); }
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); } }
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 } }
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); }
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); }
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(); } }
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(); } }
/// <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); } }
/// <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); } } }