public void ProtectedRun() { DateTime lastException = DateTime.MinValue; while (!_ct.IsCancellationRequested) { try { // any wfs fall through the cracks and are asleep but have triggers? IEnumerable <WorkflowInstanceInfo> sleeping = Enumerable.Empty <WorkflowInstanceInfo>(); var instancesQuery = new QuerySpecification { BookMark = new GenericPageBookmark { PageSize = 100 }, Where = new Filter { Rules = new Comparison[] { new Comparison { Data = WorkflowStatus.Sleeping.ToString(), Field = "Status", Test = Test.Equal } } } }; instancesQuery.BookMark = new GenericPageBookmark { PageSize = 100 }; while (instancesQuery.BookMark.More) { var qr = _instanceData.Query(instancesQuery); if (qr.Items.Any()) { sleeping = sleeping.Concat(qr.Items); } } sleeping = sleeping.ToArray(); Parallel.ForEach(sleeping, nc => { try { // check for triggers IEnumerable <WorkflowMachineState> hasTriggers = Enumerable.Empty <WorkflowMachineState>(); var hasTriggersQuery = new QuerySpecification { BookMark = new GenericPageBookmark { PageSize = 100 }, Where = new Filter { Rules = new Comparison[] { new Comparison { Field = "Parent", Data = nc.Id, Test = Test.Equal } } } }; while (hasTriggersQuery.BookMark.More) { var qr = _machineStateData.Query(hasTriggersQuery); if (qr.Items.Any()) { hasTriggers = hasTriggers.Concat(qr.Items); } } // it has some, try to acquire it if (hasTriggers.Any()) { _ct.ThrowIfCancellationRequested(); _log.InfoFormat( "Sleeping workflow {0} has {1} waiting triggers. Waking.", nc.Id, hasTriggers.Count()); TryAcquireWorkflow(nc.Id); } } catch (Exception ex) { _dblog.ErrorFormat("Problem while waking workflow {0}:{2}", nc.Id, ex.ToString()); } }); // groom completed and data IEnumerable <WorkflowInstanceInfo> completedInstances = Enumerable.Empty <WorkflowInstanceInfo>(); var completedQuery = new QuerySpecification { BookMark = new GenericPageBookmark { PageSize = 100 }, Where = new Filter { Rules = new Comparison[] { new Comparison { Data = WorkflowStatus.Complete.ToString(), Field = "Status", Test = Test.Equal } } } }; completedQuery.BookMark = new GenericPageBookmark { PageSize = 100 }; while (completedQuery.BookMark.More) { var qr = _instanceData.Query(completedQuery); if (qr.Items.Any()) { completedInstances = completedInstances.Concat(qr.Items); } } completedInstances = completedInstances.ToArray(); Parallel.ForEach(completedInstances, ci => { try { _log.InfoFormat("Grooming completed workflow instance {0}", ci.Id); _ct.ThrowIfCancellationRequested(); // delete workspaces var workspace = Catalog.Preconfigure() .Add(WorkspaceLocalConfig.WorkspaceName, WorkflowShared.WorkflowInstanceWorkspaceName(ci.Id)) .ConfiguredResolve <IWorkspace>(_workflowWorkspaceKey); workspace.DeleteWorkspace(); _ct.ThrowIfCancellationRequested(); IEnumerable <WorkflowMachineState> states = Enumerable.Empty <WorkflowMachineState>(); var msQuery = new QuerySpecification { BookMark = new GenericPageBookmark { PageSize = 100 }, Where = new Filter { Rules = new Comparison[] { new Comparison { Data = ci.Id, Field = "Parent", Test = Test.Equal } } } }; msQuery.BookMark = new GenericPageBookmark { PageSize = 100 }; while (msQuery.BookMark.More) { var qr = _machineStateData.Query(msQuery); if (qr.Items.Any()) { states = states.Concat(qr.Items); } } _machineStateData.DeleteBatch(states.ToList()); _instanceData.Delete(ci); } catch (Exception ex) { var es = string.Format( "Problem while grooming completed workflow {0}:{1}", ci.Id, ex.ToString()); _dblog.Error(es); var on = Catalog.Factory.Resolve <IApplicationAlert>(); on.RaiseAlert(ApplicationAlertKind.Unknown, es); } }); var chill = TimeSpan.FromMinutes((30.0 * _rndGroomTime.NextDouble()) + 1.0); _log.InfoFormat("Waiting {0} minutes until next sweep cycle.", chill.TotalMinutes); _ct.WaitHandle.WaitOne(chill); } catch (Exception ex) { var es = string.Format("exception running workflow host {0}", ex.TraceInformation()); _dblog.Error(es); if (DateTime.UtcNow - lastException > TimeSpan.FromMinutes(1.0)) { _log.TraceException(ex); var alert = Catalog.Factory.Resolve <IApplicationAlert>(); alert.RaiseAlert(ApplicationAlertKind.System, es); } } } }
private void RunAgent() { var autoSleepTimeout = DateTime.UtcNow + _initialSleepTimeout; var instanceTriggersQuery = new QuerySpecification { BookMark = new GenericPageBookmark { PageSize = 1000 }, Where = new Filter { Rules = new Comparison[] { new Comparison { Data = Id, Field = "InstanceTarget", Test = Test.Equal } } } }; while (_runAgent && !_ct.IsCancellationRequested) { try { // scan triggers IEnumerable <WorkflowTrigger> instTrigs = Enumerable.Empty <WorkflowTrigger>(); instanceTriggersQuery.BookMark = new GenericPageBookmark(new GenericPageBookmark { PageSize = 1000 }); do { var qr = _triggers.Query(instanceTriggersQuery); if (qr.Items.Any()) { instTrigs = instTrigs.Concat(qr.Items); } instanceTriggersQuery.BookMark = qr.Bookmark; } while (instanceTriggersQuery.BookMark.More); var myTrigs = instTrigs.ToArray().GroupBy(t => t.Route); _ct.ThrowIfCancellationRequested(); if (myTrigs.Any()) { var fireTrigs = myTrigs.Where(t => t.Key == TriggerRoutes.FireRoute); foreach (var t in fireTrigs.SelectMany()) { try { StateMachines[t.MachineContext].Fire(t.TriggerName); } catch (Exception ex) { _log.Error(ex.TraceInformation()); } _triggers.IdDelete(t.Id); _ct.ThrowIfCancellationRequested(); } var completeTrigs = myTrigs.Where(t => t.Key == TriggerRoutes.EndRoute); if (completeTrigs.Any()) { CompleteWorkflow(); _triggers.DeleteBatch(myTrigs.SelectMany().ToList()); break; } else { var napTrigs = myTrigs.Where(t => t.Key == TriggerRoutes.NapRoute); if (napTrigs.Any()) { _triggers.DeleteBatch(napTrigs.SelectMany().ToList()); if (StateMachines.Values.Any(sm => sm.CanActivate)) { // TODO: nap time variable var nextActivationTime = DateTime.UtcNow + TimeSpan.FromMinutes(60.0); Sleep(nextActivationTime); } else { // no activation triggers, so this sleep would be until triggered Sleep(); } break; } } autoSleepTimeout = DateTime.UtcNow + _autoSleepTime; } _bumpEvent.Wait(TimeSpan.FromMinutes(5.0)); _bumpEvent.Reset(); // auto sleep? if (DateTime.UtcNow > autoSleepTimeout) { //Sleep(); } } catch (OperationCanceledException) { } catch (Exception ex) { var es = string.Format("Workflow agent exception: {0}", ex); _log.Error(es); var on = Catalog.Factory.Resolve <IApplicationAlert>(); on.RaiseAlert(ApplicationAlertKind.System, es); } } }