Пример #1
0
        public static async Task ProcessMessages(string logSource,
                                                 TenantInformation tenant,
                                                 IServiceLogRepository serviceLogRepository,
                                                 IList <IWorkflowMessage> messages,
                                                 string exceptionMessagePrepender,
                                                 IWorkflowMessagingProcessor workflowMessagingProcessor)
        {
            if (messages == null || messages.Count <= 0)
            {
                return;
            }

            var processor = workflowMessagingProcessor ?? WorkflowMessagingProcessor.Instance;

            foreach (var actionMessage in messages.Where(a => a != null))
            {
                try
                {
                    await ActionMessageSender.Send((ActionMessage)actionMessage, tenant, processor);

                    string message = $"Sent {actionMessage.ActionType} message: {actionMessage.ToJSON()} with tenant id: {tenant.TenantId} to the Message queue";
                    await
                    serviceLogRepository.LogInformation(logSource, message);
                }
                catch (Exception ex)
                {
                    string message =
                        $"Error while sending {actionMessage.ActionType} message with content {actionMessage.ToJSON()}. {exceptionMessagePrepender}. Exception: {ex.Message}. StackTrace: {ex.StackTrace ?? string.Empty}";
                    await
                    serviceLogRepository.LogError(logSource, message);

                    throw;
                }
            }
        }
        public static async Task Send(IEnumerable<int> artifactIds, TenantInformation tenant, ActionMessage sourceMessage, IWorkflowMessagingProcessor workflowMessagingProcessor)
        {
            var artifacts = artifactIds?.ToList();
            if (artifacts == null || !artifacts.Any())
            {
                Logger.Log("No artifact IDs found; no need to send Artifact Changed Message", sourceMessage, tenant);
                return;
            }
            Logger.Log($"Found {artifacts.Count} artifact IDs", sourceMessage, tenant);

            var artifactsChangedMessage = new ArtifactsChangedMessage
            {
                TransactionId = sourceMessage.TransactionId,
                RevisionId = sourceMessage.RevisionId,
                UserId = sourceMessage.UserId,
                ChangeType = ArtifactChangedType.Indirect
            };

            while (artifacts.Any())
            {
                var batch = artifacts.Take(MaximumArtifactBatchSize).ToList();
                artifactsChangedMessage.ArtifactIds = batch;

                Logger.Log($"Sending Artifacts Changed Message for {batch.Count} artifact IDs: {string.Join(",", batch)}", sourceMessage, tenant);
                await ActionMessageSender.Send(artifactsChangedMessage, tenant, workflowMessagingProcessor);
                Logger.Log("Finished sending Artifacts Changed Message", sourceMessage, tenant);

                artifacts = artifacts.Skip(MaximumArtifactBatchSize).ToList();
            }
        }
        public async Task <bool> HandleUsersGroupsChangedAction(TenantInformation tenant, ActionMessage actionMessage, IBaseRepository baseRepository, IWorkflowMessagingProcessor workflowMessagingProcessor)
        {
            var message    = (UsersGroupsChangedMessage)actionMessage;
            var repository = (IUsersGroupsChangedRepository)baseRepository;

            Logger.Log($"Handling Users Groups Changed Message for change type {message.ChangeType}", message, tenant);

            if (message.ChangeType == UsersGroupsChangedType.Create)
            {
                Logger.Log("No need to send Artifacts Changed Messages when Creating Users or Groups", message, tenant);
                return(true);
            }

            Logger.Log("Getting affected artifact IDs", message, tenant);
            var artifactIds = await repository.GetAffectedArtifactIds(message.UserIds, message.GroupIds, message.RevisionId);

            await ArtifactsChangedMessageSender.Send(artifactIds, tenant, actionMessage, workflowMessagingProcessor);

            return(true);
        }
        public async Task <bool> HandleWorkflowsChangedAction(TenantInformation tenant, ActionMessage actionMessage, IBaseRepository baseRepository, IWorkflowMessagingProcessor workflowMessagingProcessor)
        {
            var message    = (WorkflowsChangedMessage)actionMessage;
            var repository = (IWorkflowsChangedRepository)baseRepository;

            Logger.Log("Getting affected artifact IDs", message, tenant);
            var workflowIds = new[]
            {
                message.WorkflowId
            };
            var artifactIds = await repository.GetAffectedArtifactIds(workflowIds, message.RevisionId);

            await ArtifactsChangedMessageSender.Send(artifactIds, tenant, actionMessage, workflowMessagingProcessor);

            return(true);
        }
        internal static async Task <bool> ProcessCreatedArtifacts(TenantInformation tenant,
                                                                  ArtifactsPublishedMessage message,
                                                                  IArtifactsPublishedRepository repository,
                                                                  IServiceLogRepository serviceLogRepository,
                                                                  IWorkflowMessagingProcessor messageProcessor,
                                                                  int transactionCommitWaitTimeInMilliSeconds = 60000)
        {
            var createdArtifacts = message?.Artifacts?.Where(p => p.IsFirstTimePublished && repository.WorkflowRepository.IsWorkflowSupported((ItemTypePredefined)p.Predefined)).ToList();

            if (createdArtifacts == null || createdArtifacts.Count <= 0)
            {
                Logger.Log("No created artifacts found", message, tenant);
                return(false);
            }
            Logger.Log($"{createdArtifacts.Count} created artifacts found", message, tenant);

            var artifactIds   = createdArtifacts.Select(a => a.Id).ToHashSet();
            var artifactInfos = (await repository.WorkflowRepository.GetWorkflowMessageArtifactInfoAsync(message.UserId, artifactIds, message.RevisionId)).ToDictionary(k => k.Id);

            Logger.Log($"{artifactInfos.Count} artifact infos found", message, tenant);
            var notificationMessages = new Dictionary <int, List <IWorkflowMessage> >();

            foreach (var createdArtifact in createdArtifacts)
            {
                WorkflowMessageArtifactInfo artifactInfo;
                if (!artifactInfos.TryGetValue(createdArtifact.Id, out artifactInfo))
                {
                    await serviceLogRepository.LogInformation(LogSource, $"Could not recover information for artifact Id: {createdArtifact.Id} and Name: {createdArtifact.Name} and Project Id: {createdArtifact.ProjectId}");

                    Logger.Log($"Could not recover information for artifact Id: {createdArtifact.Id} and Name: {createdArtifact.Name} and Project Id: {createdArtifact.ProjectId}", message, tenant);
                    continue;
                }

                var eventTriggers = await repository.WorkflowRepository.GetWorkflowEventTriggersForNewArtifactEvent(message.UserId,
                                                                                                                    new[] { createdArtifact.Id },
                                                                                                                    message.RevisionId, true);

                if (eventTriggers?.AsynchronousTriggers == null ||
                    eventTriggers.AsynchronousTriggers.Count == 0)
                {
                    Logger.Log($"Found no async triggers for artifact with ID {createdArtifact.Id}", message, tenant);
                    continue;
                }
                Logger.Log($"Found {eventTriggers.AsynchronousTriggers.Count} async triggers for artifact with ID {createdArtifact.Id}", message, tenant);

                int artifactId = createdArtifact.Id;

                var currentState = await repository.WorkflowRepository.GetStateForArtifactAsync(message.UserId, createdArtifact.Id, int.MaxValue, true);

                var actionMessages = await WorkflowEventsMessagesHelper.GenerateMessages(message.UserId,
                                                                                         message.RevisionId,
                                                                                         message.UserName,
                                                                                         message.TransactionId,
                                                                                         eventTriggers.AsynchronousTriggers,
                                                                                         artifactInfo,
                                                                                         artifactInfo.ProjectName,
                                                                                         new Dictionary <int, IList <Property> >(),
                                                                                         currentState,
                                                                                         createdArtifact.Url,
                                                                                         createdArtifact.BaseUrl,
                                                                                         createdArtifact.AncestorArtifactTypeIds,
                                                                                         repository.UsersRepository,
                                                                                         serviceLogRepository,
                                                                                         repository.WebhooksRepository,
                                                                                         repository.ProjectMetaRepository);

                if (actionMessages == null || actionMessages.Count == 0)
                {
                    continue;
                }

                if (!notificationMessages.ContainsKey(artifactId))
                {
                    notificationMessages.Add(artifactId, new List <IWorkflowMessage>());
                }

                notificationMessages[artifactId].AddRange(actionMessages);
            }

            if (notificationMessages.Count == 0)
            {
                Logger.Log("None of the created artifacts have async triggers", message, tenant);
                return(false);
            }
            Logger.Log($"Sending async trigger messages for artifacts: {string.Join(", ", notificationMessages.Select(kvp => kvp.Key))}", message, tenant);

            foreach (var notificationMessage in notificationMessages.Where(m => m.Value != null))
            {
                await WorkflowEventsMessagesHelper.ProcessMessages(LogSource,
                                                                   tenant,
                                                                   serviceLogRepository,
                                                                   notificationMessage.Value,
                                                                   $"Error on new artifact creation with Id: {notificationMessage.Key}",
                                                                   messageProcessor);
            }

            return(true);
        }
        internal static async Task <bool> ProcessUpdatedArtifacts(
            TenantInformation tenant,
            ArtifactsPublishedMessage message,
            IArtifactsPublishedRepository repository,
            IServiceLogRepository serviceLogRepository,
            IActionsParser actionsParser,
            IWorkflowMessagingProcessor messageProcessor)
        {
            var allUpdatedArtifacts = message?.Artifacts?.Where(p => !p.IsFirstTimePublished).ToList();

            if (allUpdatedArtifacts == null || allUpdatedArtifacts.Count <= 0)
            {
                Logger.Log("No updated artifacts found", message, tenant);
                return(false);
            }
            Logger.Log($"{allUpdatedArtifacts.Count} updated artifacts found", message, tenant);

            var updatedArtifacts = allUpdatedArtifacts.Where(a => a.ModifiedProperties?.Count > 0).ToList();

            if (updatedArtifacts.Count == 0)
            {
                Logger.Log("No modified properties found for updated artifacts", message, tenant);
                return(false);
            }

            // Get artifacts which have modified properties list populated
            var allArtifactsModifiedProperties = updatedArtifacts.ToDictionary(k => k.Id,
                                                                               v => v.ModifiedProperties ?? new List <PublishedPropertyInformation>());

            Logger.Log(
                $"{allArtifactsModifiedProperties.Count} artifacts found: {string.Join(", ", allArtifactsModifiedProperties.Select(k => k.Key))}",
                message, tenant, LogLevel.Debug);

            if (allArtifactsModifiedProperties.Count == 0)
            {
                return(false);
            }

            // Get property transitions for published artifact ids.
            var publishedArtifactIds   = updatedArtifacts.Select(a => a.Id).ToHashSet();
            var artifactPropertyEvents =
                await
                repository.GetWorkflowPropertyTransitionsForArtifactsAsync(message.UserId,
                                                                           message.RevisionId,
                                                                           (int)TransitionType.Property, publishedArtifactIds);

            // If no property transitions found, then call does not need to proceed
            Logger.Log($"{artifactPropertyEvents?.Count ?? 0} workflow property events found", message, tenant, LogLevel.Debug);
            if (artifactPropertyEvents == null || artifactPropertyEvents.Count == 0)
            {
                Logger.Log("No property change triggers found", message, tenant);
                return(false);
            }

            // Convert all property transitions to a dictionary with artifact id as key
            var activePropertyTransitions = new Dictionary <int, IList <SqlWorkflowEvent> >();
            var publishedArtifactEvents   = artifactPropertyEvents.Where(ape => publishedArtifactIds.Contains(ape.VersionItemId));

            // key = artifact id, value = all events
            foreach (var artifactPropertyEvent in publishedArtifactEvents)
            {
                if (activePropertyTransitions.ContainsKey(artifactPropertyEvent.VersionItemId))
                {
                    activePropertyTransitions[artifactPropertyEvent.VersionItemId].Add(artifactPropertyEvent);
                }
                else
                {
                    activePropertyTransitions.Add(artifactPropertyEvent.VersionItemId,
                                                  new List <SqlWorkflowEvent> {
                        artifactPropertyEvent
                    });
                }
            }

            var sqlWorkflowStates =
                await
                repository.GetWorkflowStatesForArtifactsAsync(message.UserId, activePropertyTransitions.Keys,
                                                              message.RevisionId);

            var workflowStates = sqlWorkflowStates.Where(w => w.WorkflowStateId > 0).ToDictionary(k => k.ArtifactId);

            Logger.Log(
                $"{workflowStates.Count} workflow states found for artifacts: {string.Join(", ", workflowStates.Select(k => k.Key))}",
                message, tenant, LogLevel.Debug);
            if (workflowStates.Count == 0)
            {
                return(false);
            }

            // Get project names
            var projectIds = updatedArtifacts.Select(a => a.ProjectId).ToList();
            var projects   = await repository.GetProjectNameByIdsAsync(projectIds);

            Logger.Log($"{projects.Count} project names found for project IDs: {string.Join(", ", projectIds)}", message, tenant,
                       LogLevel.Debug);

            var notificationMessages = new Dictionary <int, List <IWorkflowMessage> >();

            // For artifacts in active property transitions
            foreach (var artifactId in activePropertyTransitions.Keys)
            {
                Logger.Log($"Processing artifact with ID: {artifactId}", message, tenant, LogLevel.Debug);

                var artifactTransitionInfo = activePropertyTransitions[artifactId];
                var notifications          = actionsParser.GetNotificationActions(artifactTransitionInfo).ToList();
                Logger.Log($"{notifications.Count} Notification actions found", message, tenant, LogLevel.Debug);
                if (notifications.Count == 0)
                {
                    continue;
                }

                List <PublishedPropertyInformation> artifactModifiedProperties;
                if (!allArtifactsModifiedProperties.TryGetValue(artifactId, out artifactModifiedProperties))
                {
                    Logger.Log($"modified properties not found for {artifactId}", message, tenant, LogLevel.Debug);
                    continue;
                }

                Logger.Log($"{artifactModifiedProperties?.Count ?? 0} modified properties found", message, tenant,
                           LogLevel.Debug);
                if (artifactModifiedProperties == null || !artifactModifiedProperties.Any())
                {
                    continue;
                }

                SqlWorkFlowStateInformation currentStateInfo;
                if (!workflowStates.TryGetValue(artifactId, out currentStateInfo))
                {
                    continue;
                }

                var modifiedSystemPropertiesSet = artifactModifiedProperties.Where(a => a.PredefinedType == (int)PropertyTypePredefined.Name ||
                                                                                   a.PredefinedType == (int)PropertyTypePredefined.Description)
                                                  .Select(a => (PropertyTypePredefined)a.PredefinedType)
                                                  .ToHashSet();

                await ProcessSystemPropertyChange(tenant, message, repository, notifications, modifiedSystemPropertiesSet, currentStateInfo, updatedArtifacts, artifactId, workflowStates, projects, notificationMessages);

                var modifiedCustomPropertiesSet = artifactModifiedProperties.Where(a => a.PredefinedType == (int)PropertyTypePredefined.CustomGroup)
                                                  .Select(a => a.TypeId)
                                                  .ToHashSet();

                // Process custom properties
                Logger.Log(
                    $"{modifiedCustomPropertiesSet.Count} instance property type IDs being located: {string.Join(", ", modifiedCustomPropertiesSet)}",
                    message, tenant, LogLevel.Debug);

                await ProcessCustomPropertyChange(tenant, message, repository, notifications, modifiedCustomPropertiesSet, currentStateInfo, updatedArtifacts, artifactId, workflowStates, projects, notificationMessages);
            }

            if (notificationMessages.Count == 0)
            {
                Logger.Log("None of the modified properties have property change notification triggers", message, tenant);
                return(false);
            }
            Logger.Log($"Sending property change notifications for artifacts: {string.Join(", ", notificationMessages.Select(kvp => kvp.Key))}", message, tenant);

            foreach (var notificationMessage in notificationMessages)
            {
                await WorkflowEventsMessagesHelper.ProcessMessages(LogSource,
                                                                   tenant,
                                                                   serviceLogRepository,
                                                                   notificationMessage.Value,
                                                                   $"Error on new artifact creation with Id: {notificationMessage.Key}",
                                                                   messageProcessor);
            }

            return(true);
        }
Пример #7
0
        public async Task <bool> HandlePropertyItemTypesChangedAction(TenantInformation tenant, ActionMessage actionMessage, IBaseRepository baseRepository, IWorkflowMessagingProcessor workflowMessagingProcessor)
        {
            var message    = (PropertyItemTypesChangedMessage)actionMessage;
            var repository = (IPropertyItemTypesChangedRepository)baseRepository;

            var revisionId    = message.RevisionId;
            var isInstance    = message.IsStandard;
            var itemTypes     = message.ItemTypeIds?.ToList();
            var propertyTypes = message.PropertyTypeIds?.ToList();

            var artifactIds = new List <int>();

            if (itemTypes != null && itemTypes.Any())
            {
                Logger.Log("Getting affected artifact IDs for item types", message, tenant);
                var affectedArtifacts = await repository.GetAffectedArtifactIdsForItemTypes(itemTypes, isInstance, revisionId);

                Logger.Log($"Received {affectedArtifacts.Count} affected artifact IDs for item types", message, tenant);
                artifactIds.AddRange(affectedArtifacts);
            }

            if (propertyTypes != null && propertyTypes.Any())
            {
                Logger.Log("Getting affected artifact IDs for property types", message, tenant);
                var affectedArtifacts = await repository.GetAffectedArtifactIdsForPropertyTypes(propertyTypes, isInstance, revisionId);

                Logger.Log($"Received {affectedArtifacts.Count} affected artifact IDs for property types", message, tenant);
                artifactIds.AddRange(affectedArtifacts);
            }

            await ArtifactsChangedMessageSender.Send(artifactIds, tenant, actionMessage, workflowMessagingProcessor);

            return(true);
        }
Пример #8
0
        public static async Task Send(ActionMessage message, TenantInformation tenant, IWorkflowMessagingProcessor workflowMessagingProcessor)
        {
            Logger.Log($"Sending {message.ActionType} message with transaction ID '{message.TransactionId}' for tenant '{tenant.TenantId}': {message.ToJSON()}", message, tenant);
            await workflowMessagingProcessor.SendMessageAsync(tenant.TenantId, message);

            Logger.Log($"Successfully sent {message.ActionType} message", message, tenant);
        }