protected override async Task ProcessItem(string itemId, CancellationToken cancellationToken) { if (!await _lockProvider.AcquireLock($"evt:{itemId}", cancellationToken)) { Logger.LogInformation($"Event locked {itemId}"); return; } try { cancellationToken.ThrowIfCancellationRequested(); var evt = await _eventRepository.GetEvent(itemId); if (evt.EventTime <= _datetimeProvider.UtcNow) { IEnumerable <EventSubscription> subs = null; if (evt.EventData is ActivityResult) { var activity = await _subscriptionRepository.GetSubscription((evt.EventData as ActivityResult).SubscriptionId); if (activity == null) { Logger.LogWarning($"Activity already processed - {(evt.EventData as ActivityResult).SubscriptionId}"); await _eventRepository.MarkEventProcessed(itemId); return; } subs = new List <EventSubscription>() { activity }; } else { subs = await _subscriptionRepository.GetSubscriptions(evt.EventName, evt.EventKey, evt.EventTime); } var toQueue = new List <string>(); var complete = true; foreach (var sub in subs.ToList()) { complete = complete && await SeedSubscription(evt, sub, toQueue, cancellationToken); } if (complete) { await _eventRepository.MarkEventProcessed(itemId); } foreach (var eventId in toQueue) { await QueueProvider.QueueWork(eventId, QueueType.Event); } } } finally { await _lockProvider.ReleaseLock($"evt:{itemId}"); } }
/// <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); } }
protected override async Task ProcessItem(string itemId, CancellationToken cancellationToken) { if (!await _lockProvider.AcquireLock(itemId, cancellationToken)) { Logger.LogInformation("Workflow locked {0}", itemId); return; } WorkflowInstance workflow = null; WorkflowExecutorResult result = null; var persistenceStore = _persistenceStorePool.Get(); try { try { cancellationToken.ThrowIfCancellationRequested(); workflow = await persistenceStore.GetWorkflowInstance(itemId); if (workflow.Status == WorkflowStatus.Runnable) { var executor = _executorPool.Get(); try { result = await executor.Execute(workflow); } finally { _executorPool.Return(executor); await persistenceStore.PersistWorkflow(workflow); await QueueProvider.QueueWork(itemId, QueueType.Index); } } } finally { await _lockProvider.ReleaseLock(itemId); if ((workflow != null) && (result != null)) { foreach (var sub in result.Subscriptions) { await SubscribeEvent(sub, persistenceStore); } await persistenceStore.PersistErrors(result.Errors); var readAheadTicks = _datetimeProvider.Now.Add(Options.PollInterval).ToUniversalTime().Ticks; if ((workflow.Status == WorkflowStatus.Runnable) && workflow.NextExecution.HasValue && workflow.NextExecution.Value < readAheadTicks) { new Task(() => FutureQueue(workflow, cancellationToken)).Start(); } } } } finally { _persistenceStorePool.Return(persistenceStore); } }
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); if (persistSate) { await _persistenceStore.PersistWorkflow(wf, token); } } } finally { await _lockService.ReleaseLock(id); } if (persistSate) { await _queueService.QueueWork(id, QueueType.Index); } return(wf); }
/// <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); } } }
private async Task PollWorkflows() { var activity = WorkflowActivity.StartPoll("workflows"); 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); activity?.RecordException(ex); } } 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); activity?.RecordException(ex); } finally { activity?.Dispose(); } }