public IEnumerable <WorkflowInstanceInfo> GetInstances(WorkflowStatus?filter = null) { if (null == filter) { var queryResult = _instanceData.All(); return(queryResult.Items.EmptyIfNull()); } else { var qs = new QuerySpecification { BookMark = new GenericPageBookmark { PageSize = 1000 }, Where = new Filter { PredicateJoin = PredicateJoin.And, Rules = new Comparison[] { new Comparison { Data = filter.Value.EnumName(), Field = "Status", Test = Test.Equal } } } }; var queryResult = _instanceData.Query(qs); return(queryResult.Items.EmptyIfNull()); } }
public WorkflowContext(string persistenceContext, string machineContext, string initialState, string repositoryKey) { _persistenceContext = persistenceContext; _machineContext = machineContext; _cachedState = initialState; _machineStateData = Catalog.Preconfigure().ConfigureWorkflowDataRepository <WorkflowMachineState>() .ConfiguredResolve <IDataRepositoryService <WorkflowMachineState, WorkflowMachineState, DataEnvelope <WorkflowMachineState, NoMetadata>, NoMetadata, DatumEnvelope <WorkflowMachineState, NoMetadata>, NoMetadata> > (repositoryKey); WorkflowMachineState current = null; var qs = new QuerySpecification { BookMark = new GenericPageBookmark { PageSize = 100 }, Where = new Filter { PredicateJoin = PredicateJoin.And, Rules = new Comparison[] { new Comparison { Data = _persistenceContext, Field = "Parent", Test = Test.Equal }, new Comparison { Data = _machineContext, Field = "StateMachine", Test = Test.Equal } } } }; var queryResult = _machineStateData.Query(qs).Items.EmptyIfNull(); current = queryResult.FirstOrDefault(); if (null != current) { _cachedState = current.State; _cachedId = current.Id; } else { _cachedId = string.Format("MS{0}-{1}", _persistenceContext, _machineContext); ChangeState(_cachedState); } }
public virtual TSummaryPackageType GetQuery(QuerySpecification qs) { var retval = _dataRepository.Query(qs); if (null == retval) { throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound)); } return(retval); }
public string GetState(string context) { var qs = new QuerySpecification { BookMark = new GenericPageBookmark { PageSize = 100 }, Where = new Filter { PredicateJoin = PredicateJoin.And, Rules = new[] { new Comparison { Data = Id, Field = "Parent", Test = Test.Equal }, new Comparison { Data = context, Field = "StateMachine", Test = Test.Equal } } } }; var st = string.Empty; var found = _machineStateData.Query(qs).Items; if (found.Any()) { st = found.First().State; } return(st); }
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); } } } }
public bool OnStart() { _listener.Listen( new KeyValuePair <Type, Action <object, CancellationToken, IMessageAcknowledge> >(typeof(WakeWorkflowJob), WakeWorkflow), new KeyValuePair <Type, Action <object, CancellationToken, IMessageAcknowledge> >(typeof(WorkflowCreate), NewWorkflowInstance), new KeyValuePair <Type, Action <object, CancellationToken, IMessageAcknowledge> >(typeof(WorkflowStateMachineRetry), FireRetryMsg), new KeyValuePair <Type, Action <object, CancellationToken, IMessageAcknowledge> >(typeof(FireWorkflowTriggerJob), FireTriggerJobMsg)); _broadcastListener.Listen(new KeyValuePair <Type, Action <object, CancellationToken, IMessageAcknowledge> >(typeof(WorkflowTrigger), DistributeWorkflowTriggers)); var hostEnvironment = Catalog.Factory.Resolve <IHostEnvironment>(); var hostId = hostEnvironment.GetCurrentHostIdentifier(HostEnvironmentConstants.DefaultHostScope); var instancesQuery = new QuerySpecification { BookMark = new GenericPageBookmark { PageSize = 100 }, Where = new Filter { Rules = new Comparison[] { new Comparison { Data = WorkflowStatus.Complete.ToString(), Field = "Status", Test = Test.NotEqual } } } }; Task.Factory.StartNew(() => { // get this host's chunk of workflow instances to run. Random rnd = GoodSeedRandom.Create(); bool done = false; bool first = true; DateTime lastException = DateTime.MinValue; while (!done) { try { int acquired = 0; IEnumerable <WorkflowInstanceInfo> instances = Enumerable.Empty <WorkflowInstanceInfo>(); instancesQuery.BookMark = new GenericPageBookmark { PageSize = 100 }; while (instancesQuery.BookMark.More) { var qr = _instanceData.Query(instancesQuery); if (qr.Items.Any()) { instances = instances.Concat(qr.Items); } } instances = instances.ToArray(); IEnumerable <WorkflowInstanceInfo> tryInstances; // first pass, pick out existing workflows in a pattern less // likely to interfere with other workflow hosts trying to acquire if (first) { int startAt; startAt = rnd.Next(3) * 3; if (startAt > instances.Count()) { startAt = rnd.Next(instances.Count() / 3); } tryInstances = instances.TakeEvery(startAt, 3); first = false; } else { // subsequent passes, be greedy tryInstances = instances; } int waitDur; foreach (var inst in tryInstances) { if (TryAcquireWorkflow(inst.Id) != null) { acquired++; _log.InfoFormat("Host {0} acquired workflow instance {1} ...", hostId, inst.Id); // give other hosts a little space to take some. waitDur = rnd.Next(160); Thread.Sleep(waitDur); } else { _log.InfoFormat( "Host {0} could not acquire workflow instance {1} ...", hostId, inst.Id); } } if (!first && acquired == 0) { done = true; } waitDur = rnd.Next(7654); _log.InfoFormat( "Host {0} acquired {1} pre-existing workflows, waiting {2} milliseconds to try to attain more.", hostId, acquired, waitDur); Thread.Sleep(waitDur); } 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); } } } }); return(true); }
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); } } }