public WorkflowCatalog() { _wfConfig = Catalog.Factory.Resolve <IConfig>(SpecialFactoryContexts.Routed); var host = WorkflowShared.GetMessageQueueHost(_wfConfig); WorkflowShared.DeclareWorkflowExchanges(host, _wfConfig[WorkflowConfiguration.WorkflowMessagingKey]); _instanceData = Catalog.Preconfigure().ConfigureWorkflowDataRepository <WorkflowInstanceInfo>() .ConfiguredResolve <IDataRepositoryService <WorkflowInstanceInfo, WorkflowInstanceInfo, DataEnvelope <WorkflowInstanceInfo, NoMetadata>, NoMetadata, DatumEnvelope <WorkflowInstanceInfo, NoMetadata>, NoMetadata> > (_wfConfig[WorkflowConfiguration.WorkflowDataRepositoryKey]); _sender = Catalog.Preconfigure() .Add(MessagePublisherLocalConfig.HostConnectionString, host) .Add(MessagePublisherLocalConfig.ExchangeName, WorkflowShared.WorkflowExchange) .ConfiguredResolve <IMessagePublisher>(_wfConfig[WorkflowConfiguration.WorkflowMessagingKey]); }
private static IDistributedMutex ConstructLock(string instanceId) { return(Catalog.Preconfigure() .Add(DistributedMutexLocalConfig.Name, WorkflowShared.WorkflowInstanceLockName(instanceId)) .Add(DistributedMutexLocalConfig.UnusedExpirationSeconds, 60) .ConfiguredResolve <IDistributedMutex>()); }
private void Initialize(WorkflowHost host, string templateData) { _log = ClassLogger.Create(GetType()); _dblog = DebugOnlyLogger.Create(_log); _host = host; _workspaceContainerName = WorkflowShared.WorkflowInstanceWorkspaceName(Id); Workspace = Catalog.Preconfigure() .Add(WorkspaceLocalConfig.WorkspaceName, _workspaceContainerName) .ConfiguredResolve <IWorkspace>(_workflowWorkspaceKey); if (null == _wfLock) { _wfLock = ConstructLock(Id); } SpecifyUsingTemplate(templateData); var instance = new WorkflowInstanceInfo { Id = Id, TemplateName = Name, LastActivity = DateTime.UtcNow, NextActivationTime = DateTime.UtcNow, Status = WorkflowStatus.Active.ToString(), }; _instanceData.Store(instance); }
/// <summary> /// Try to lock and host a pre-existing workflow. /// </summary> /// <param name="workflowId"> </param> /// <returns> </returns> private WorkflowAgent TryAcquireWorkflow(string workflowId) { WorkflowAgent acquired = null; var wfMutex = Catalog.Preconfigure() .Add(DistributedMutexLocalConfig.Name, WorkflowShared.WorkflowInstanceLockName(workflowId)) .ConfiguredResolve <IDistributedMutex>(); if (wfMutex.Open()) { try { var wftemp = GetWorkflowTemplate(workflowId); if (!string.IsNullOrWhiteSpace(wftemp)) { acquired = WorkflowAgent.AcquireSleepingOnLocked(wfMutex, this, workflowId, _ct, wftemp, _workflowDataRepositoryKey, _workflowMessagingKey, _workflowWorkspaceKey); if (null != acquired) { if (_agents.TryAdd(workflowId, acquired)) { acquired.Start(); } else { _dblog.WarnFormat("Strange: locked workflow {0} but couldn't add it", workflowId); } } } } catch (SynchronizationLockException) { _dblog.InfoFormat("Synchronization lock exception while trying to acquire {0}", workflowId); wfMutex.Release(); } catch (WorkflowTemplateException wfex) { var es = string.Format("Error loading template for workflow! {0}: {1}", workflowId, wfex); _log.Error(es); var on = Catalog.Factory.Resolve <IApplicationAlert>(); on.RaiseAlert(ApplicationAlertKind.Unknown, es); wfMutex.Release(); } catch (Exception ex) { var es = string.Format("Error while acquiring workflow, {0}", ex); _log.Error(es); var on = Catalog.Factory.Resolve <IApplicationAlert>(); on.RaiseAlert(ApplicationAlertKind.Unknown, es); wfMutex.Release(); } } else { _dblog.InfoFormat("Could not lock {0}", workflowId); } return(acquired); }
public void OnStop() { try { _agents.Values.ForEach(a => a.Stop()); _listener.Dispose(); _broadcastListener.Dispose(); WorkflowShared.RemoveQueueFromWorkflowExchange(_queueConnection, _hostId, _workflowMessagingKey); WorkflowShared.RemoveQueueFromWorkflowBroadcast(_queueConnection, WorkflowShared.WorkflowFanoutExchange, _workflowMessagingKey); } catch (Exception ex) { _dblog.WarnFormat("Exception while stopping workflow host: {0}", ex.ToString()); } }
public Workflow(string instance) { var cf = Catalog.Factory.Resolve <IConfig>(SpecialFactoryContexts.Routed); var host = WorkflowShared.GetMessageQueueHost(cf); WorkflowShared.DeclareWorkflowExchanges(host, cf[WorkflowConfiguration.WorkflowMessagingKey]); _instance = instance; _machineStateData = Catalog.Preconfigure().ConfigureWorkflowDataRepository <WorkflowMachineState>() .ConfiguredResolve <IDataRepositoryService <WorkflowMachineState, WorkflowMachineState, DataEnvelope <WorkflowMachineState, NoMetadata>, NoMetadata, DatumEnvelope <WorkflowMachineState, NoMetadata>, NoMetadata> > (cf[WorkflowConfiguration.WorkflowDataRepositoryKey]); _instanceData = Catalog.Preconfigure().ConfigureWorkflowDataRepository <WorkflowInstanceInfo>() .ConfiguredResolve <IDataRepositoryService <WorkflowInstanceInfo, WorkflowInstanceInfo, DataEnvelope <WorkflowInstanceInfo, NoMetadata>, NoMetadata, DatumEnvelope <WorkflowInstanceInfo, NoMetadata>, NoMetadata> > (cf[WorkflowConfiguration.WorkflowDataRepositoryKey]); _triggers = Catalog.Preconfigure().ConfigureWorkflowDataRepository <WorkflowTrigger>() .ConfiguredResolve <IDataRepositoryService <WorkflowTrigger, WorkflowTrigger, DataEnvelope <WorkflowTrigger, NoMetadata>, NoMetadata, DatumEnvelope <WorkflowTrigger, NoMetadata>, NoMetadata> > (cf[WorkflowConfiguration.WorkflowDataRepositoryKey]); _sender = Catalog.Preconfigure() .Add(MessagePublisherLocalConfig.HostConnectionString, host) .Add(MessagePublisherLocalConfig.ExchangeName, WorkflowShared.WorkflowFanoutExchange) .ConfiguredResolve <IMessagePublisher>(cf[WorkflowConfiguration.WorkflowMessagingKey]); _workspaceKey = cf[WorkflowConfiguration.WorkflowWorkspaceKey]; RefreshInstanceInfo(); }
public WorkflowHost() { var cf = Catalog.Factory.Resolve <IConfig>(SpecialFactoryContexts.Routed); _queueConnection = WorkflowShared.GetMessageQueueHost(cf); _wfTemplates = Catalog.Preconfigure() .Add(BlobContainerLocalConfig.ContainerName, WFHostContainerName) .Add(BlobContainerLocalConfig.OptionalAccess, EntityAccess.Private) .Add(BlobContainerLocalConfig.OptionalContentType, "application/json") .ConfiguredResolve <IFilesContainer>(); _stringResources = Catalog.Factory.Resolve <StringResourcesCache>(); var hostEnvironment = Catalog.Factory.Resolve <IHostEnvironment>(); var _hostId = hostEnvironment.GetCurrentHostIdentifier(HostEnvironmentConstants.DefaultHostScope); WorkflowShared.DeclareWorkflowExchanges(_queueConnection, cf[WorkflowConfiguration.WorkflowMessagingKey]); WorkflowShared.AttachQueueToWorkflowExchange(_queueConnection, _hostId, cf[WorkflowConfiguration.WorkflowMessagingKey]); WorkflowShared.AttachedQueueToWorkflowBroadcast(_queueConnection, _hostId, cf[WorkflowConfiguration.WorkflowMessagingKey]); _publisher = Catalog.Preconfigure() .Add(MessagePublisherLocalConfig.HostConnectionString, _queueConnection) .Add(MessagePublisherLocalConfig.ExchangeName, WorkflowShared.WorkflowExchange) .ConfiguredResolve <IMessagePublisher>(cf[WorkflowConfiguration.WorkflowMessagingKey]); _broadcaster = Catalog.Preconfigure() .Add(MessagePublisherLocalConfig.HostConnectionString, _queueConnection) .Add(MessagePublisherLocalConfig.ExchangeName, WorkflowShared.WorkflowFanoutExchange) .ConfiguredResolve <IMessagePublisher>(cf[WorkflowConfiguration.WorkflowMessagingKey]); _listener = Catalog.Preconfigure() .Add(MessageListenerLocalConfig.HostConnectionString, _queueConnection) .Add(MessageListenerLocalConfig.ExchangeName, WorkflowShared.WorkflowExchange) .Add(MessageListenerLocalConfig.QueueName, _hostId) .ConfiguredResolve <IMessageListener>(cf[WorkflowConfiguration.WorkflowMessagingKey]); _broadcastListener = Catalog.Preconfigure() .Add(MessageListenerLocalConfig.HostConnectionString, _queueConnection) .Add(MessageListenerLocalConfig.ExchangeName, WorkflowShared.WorkflowFanoutExchange) .Add(MessageListenerLocalConfig.QueueName, _hostId) .ConfiguredResolve <IMessageListener>(cf[WorkflowConfiguration.WorkflowMessagingKey]); _machineStateData = Catalog.Preconfigure().ConfigureWorkflowDataRepository <WorkflowMachineState>() .ConfiguredResolve <IDataRepositoryService <WorkflowMachineState, WorkflowMachineState, DataEnvelope <WorkflowMachineState, NoMetadata>, NoMetadata, DatumEnvelope <WorkflowMachineState, NoMetadata>, NoMetadata> > (cf[WorkflowConfiguration.WorkflowDataRepositoryKey]); _instanceData = Catalog.Preconfigure().ConfigureWorkflowDataRepository <WorkflowInstanceInfo>() .ConfiguredResolve <IDataRepositoryService <WorkflowInstanceInfo, WorkflowInstanceInfo, DataEnvelope <WorkflowInstanceInfo, NoMetadata>, NoMetadata, DatumEnvelope <WorkflowInstanceInfo, NoMetadata>, NoMetadata> > (cf[WorkflowConfiguration.WorkflowDataRepositoryKey]); _triggers = Catalog.Preconfigure().ConfigureWorkflowDataRepository <WorkflowTrigger>() .ConfiguredResolve <IDataRepositoryService <WorkflowTrigger, WorkflowTrigger, DataEnvelope <WorkflowTrigger, NoMetadata>, NoMetadata, DatumEnvelope <WorkflowTrigger, NoMetadata>, NoMetadata> > (cf[WorkflowConfiguration.WorkflowDataRepositoryKey]); _workflowDataRepositoryKey = cf[WorkflowConfiguration.WorkflowDataRepositoryKey]; _workflowMessagingKey = cf[WorkflowConfiguration.WorkflowMessagingKey]; _workflowWorkspaceKey = cf[WorkflowConfiguration.WorkflowWorkspaceKey]; }
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); } } } }