示例#1
0
        private void RegisterSubscriptionClientMessageHandler()
        {
            _subscriptionClient.RegisterMessageHandler(
                async(message, token) =>
            {
                var responseId = message.CorrelationId;
                var eventType  = (EventType)Enum.Parse(typeof(EventType), message.UserProperties[ServiceBusConstants.UserPropertyEventType] as string);
                //var eventName = (EventName)Enum.Parse(typeof(EventName), message.UserProperties[ServiceBusConstants.UserPropertyEventName] as string);
                var eventName           = (EventName)Enum.Parse(typeof(EventName), message.Label as string);
                var eventIndexInFlowMap = Int32.Parse(message.UserProperties[ServiceBusConstants.UserPropertyEventIndexInFlowMap].ToString());
                var messageData         = Encoding.UTF8.GetString(message.Body);
                var payLoad             = JsonConvert.DeserializeObject <BasePayLoad>(messageData);

                SedaEvent sedaEvent = new SedaEvent(
                    responseId,
                    eventType,
                    payLoad,
                    eventName,
                    eventIndexInFlowMap
                    );

                await this._messageProcessor.ProcessMessageAsync(sedaEvent);
                // Complete the message so that it is not received again.
                await _subscriptionClient.CompleteAsync(message.SystemProperties.LockToken);
            },
                new MessageHandlerOptions(ExceptionReceivedHandler)
            {
                MaxConcurrentCalls = this._azureServiceBusSettings.MaxConcurrentCalls, AutoComplete = false
            });
        }
示例#2
0
        private void RegisterSubscriptionClientMessageHandler()
        {
            _subscriptionClient.RegisterMessageHandler(
                async(message, token) =>
            {
                SedaEvent sedaEvent           = new SedaEvent();
                sedaEvent.ResponseId          = message.CorrelationId;
                sedaEvent.To                  = (SedaService)Enum.Parse(typeof(SedaService), message.To);
                sedaEvent.From                = (SedaService)Enum.Parse(typeof(SedaService), message.UserProperties[UserPropertyFrom] as string);
                sedaEvent.CmsOperation        = (CmsOperation)Enum.Parse(typeof(CmsOperation), message.UserProperties[UserPropertyCmsOperation] as string);
                sedaEvent.EventType           = (EventType)Enum.Parse(typeof(EventType), message.UserProperties[UserPropertyEventType] as string);
                sedaEvent.Priority            = (Priority)Enum.Parse(typeof(Priority), message.UserProperties[UserPropertyPriority] as string);
                sedaEvent.EventName           = (EventName)Enum.Parse(typeof(EventName), message.UserProperties[UserPropertyEventName] as string);
                sedaEvent.EventIndexInFlowMap = Int32.Parse(message.UserProperties[UserPropertyEventIndexInFlowMap].ToString());
                var messageData               = Encoding.UTF8.GetString(message.Body);
                sedaEvent.PayLoad             = JsonConvert.DeserializeObject <BasePayLoad>(messageData);

                await ProcessEvent(sedaEvent);
                // Complete the message so that it is not received again.
                await _subscriptionClient.CompleteAsync(message.SystemProperties.LockToken);
            },
                new MessageHandlerOptions(ExceptionReceivedHandler)
            {
                MaxConcurrentCalls = this._azureServiceBusSettings.MaxConcurrentCalls, AutoComplete = false
            });
        }
        public async Task ProcessMessageAsync(SedaEvent sedaEvent)
        {
            Type eventHandlerType  = null;
            var  responseSedaEvent = sedaEvent;

            if (_eventHandlerRegistry.HasHandlersForEvent(sedaEvent.EventName))
            {
                try
                {
                    eventHandlerType = _eventHandlerRegistry.GetHandlerForEvent(sedaEvent.EventName);
                    var     eventHandlerInstance = this._serviceProvider.GetService(eventHandlerType);
                    var     concreteType         = typeof(IEventHandler <>).MakeGenericType(eventHandlerType);
                    dynamic eventHandlerResult   = await(Task <ExpandoObject>) concreteType.GetMethod("Handle").Invoke(eventHandlerInstance, new object[] { sedaEvent });

                    EventTypeResponseSuccessPayLoad responsePayLoad = new EventTypeResponseSuccessPayLoad();
                    responsePayLoad.Request  = sedaEvent.PayLoad.Request;
                    responsePayLoad.Response = eventHandlerResult;

                    responseSedaEvent.PayLoad   = responsePayLoad;
                    responseSedaEvent.EventType = EventType.ResponseSuccess;
                    await this._messagePublisher.PublishAsync(responseSedaEvent);
                }
                catch (Exception ex)
                {
                    // The event handlers would retry (Retry policies to be configured - TODO) the operations on the message
                    // Will throw an exception when they cannot process the message
                    // So we are not depending on message to be re-processed.

                    var exceptionDetail = new ExceptionDetail()
                    {
                        ExceptionMessage         = ex.Message,
                        StackTrace               = ex.StackTrace,
                        InnerExceptionMessage    = ex.InnerException != null ? ex.InnerException.Message : null,
                        InnerExceptionStackTrace = ex.InnerException != null ? ex.InnerException.StackTrace : null
                    };

                    var errorResponse = new ErrorResponse()
                    {
                        Message         = "Error occured in execution of: " + eventHandlerType.ToString(),
                        ExceptionDetail = exceptionDetail
                    };

                    var errorResponsePayLoad = new EventTypeResponseFailurePayLoad()
                    {
                        Failure = errorResponse
                    };

                    responseSedaEvent.PayLoad   = errorResponsePayLoad;
                    responseSedaEvent.EventType = EventType.ResponseFailure;
                    await this._messagePublisher.PublishAsync(responseSedaEvent);
                }
            }
            else
            {
                // TODO log warning
            }
        }
示例#4
0
        public async Task <IActionResult> ValidateRepository([FromBody] ValidateRepositoryRequest request)
        {
            var result = await this._responseGenerator.CreateResponseAsync(CmsOperation.GetProjects);

            BasePayLoad payLoad = new BasePayLoad();

            payLoad.Request = request;
            SedaEvent sedaEvent = new SedaEvent(result._id, SedaService.Orchestrator, SedaService.CMS, EventType.Request, CmsOperation.ValidateRepository, Priority.One, payLoad);

            await this._eventBusMessagePublisher.PublishAsync(sedaEvent);

            BaseApiResponse apiResponse = new BaseApiResponse();

            apiResponse.ResponseId = result._id;
            return(Ok(apiResponse));
        }
示例#5
0
        public async Task PublishAsync(SedaEvent sedaEvent)
        {
            var message = new Message()
            {
                CorrelationId = sedaEvent.ResponseId,
                Label         = sedaEvent.EventName.ToString()
            };

            message.UserProperties.Add(ServiceBusConstants.UserPropertyEventType, sedaEvent.EventType.ToString());
            message.UserProperties.Add(ServiceBusConstants.UserPropertyEventIndexInFlowMap, sedaEvent.EventIndexInFlowMap);

            var jsonString = JsonConvert.SerializeObject(sedaEvent.PayLoad);

            message.Body = Encoding.UTF8.GetBytes(jsonString);

            await this._topicClient.SendAsync(message);
        }
示例#6
0
        public async Task PublishAsync(SedaEvent sedaEvent)
        {
            var message = new Message()
            {
                CorrelationId = sedaEvent.ResponseId,
                To            = sedaEvent.To.ToString()
            };

            message.UserProperties.Add(UserPropertyFrom, sedaEvent.From.ToString());
            message.UserProperties.Add(UserPropertyCmsOperation, sedaEvent.CmsOperation.ToString());
            message.UserProperties.Add(UserPropertyEventType, sedaEvent.EventType.ToString());
            message.UserProperties.Add(UserPropertyPriority, sedaEvent.Priority.ToString());
            message.UserProperties.Add(UserPropertyEventIndexInFlowMap, sedaEvent.EventIndexInFlowMap);
            message.UserProperties.Add(UserPropertyEventName, sedaEvent.EventName.ToString());

            var jsonString = JsonConvert.SerializeObject(sedaEvent.PayLoad);

            message.Body = Encoding.UTF8.GetBytes(jsonString);

            await this._topicClient.SendAsync(message);
        }
        public async Task ProcessMessageAsync(SedaEvent sedaEvent)
        {
            var responseObject = await this._responseRepository.GetDocumentAsync(sedaEvent.ResponseId);

            var flowMap = responseObject.FlowMap;

            switch (sedaEvent.EventType)
            {
            case EventType.Request:
                // Need to raise the first set of events from the Map
                var nextEventSet = flowMap.GetNextSetofEvents(-1);
                foreach (var eventToRaise in nextEventSet)
                {
                    var eventMessage = new SedaEvent(
                        sedaEvent.ResponseId,
                        EventType.Request,
                        sedaEvent.PayLoad,
                        eventToRaise.EventName,
                        eventToRaise.Index
                        );
                    // Set the Event Status to Wait
                    await this._responseRepository.UpdateSpecificElementByFilterAsync(
                        x => x._id == sedaEvent.ResponseId && x.FlowMap.Events.Any(y => y.Index == eventToRaise.Index),
                        x => x.FlowMap.Events[-1].Status,
                        EventStatus.Wait);

                    await this._messagePublisher.PublishAsync(eventMessage);
                }
                break;

            case EventType.ResponseSuccess:
                // Update the current event status in DB
                await this._responseRepository.UpdateSpecificElementByFilterAsync(
                    x => x._id == sedaEvent.ResponseId && x.FlowMap.Events.Any(y => y.Index == sedaEvent.EventIndexInFlowMap),
                    x => x.FlowMap.Events[-1].Status,
                    EventStatus.Success);

                // Get the latest response status - Is the response already marked as complete,
                // this can happen if a failure occurred with one of the other parallel events within the group.
                // If so, dont need to do anything, just return
                if (responseObject.Status == EntityStatus.Error)
                {
                    break;
                }
                // Check if the entire operation is complete (current one could be the last pending event)
                // if so, update the response status to OK and add the response to response content
                // send FCM notification that operation is complete with success
                // return
                // ?? ToDo: multiple success events in parallel (See if only one thread can update the response status through MongoDB findAndModify()
                // and only that thread raises the FCM notification
                var latestResponseObj = await this._responseRepository.GetDocumentAsync(sedaEvent.ResponseId);

                if (latestResponseObj.FlowMap.IsOperationComplete)
                {
                    latestResponseObj.Content = currentCmsMessage.CMSMessageBody;
                    latestResponseObj.Status  = EntityStatus.Ok;
                    await this._responseRepository.ReplaceElementAsync(sedaEvent.ResponseId, latestResponseObj);
                    await SendOperationCompleteNotificationAsync(latestResponseObj);

                    break;
                }
                // If the whole operation is not complete, check if all events from the current Event Group are complete
                // if so, raise the next set of events.
                // TODO: (?? multiple success events in parallel within the same group.
                // Need to have a flag to mark the group as complete, whichever thread gets that update will raise next set of events)
                if (latestResponseObj.FlowMap.GetCompleteStatusForEventGroupByEventIndex(sedaEvent.EventIndexInFlowMap))
                {
                    nextEventSet = flowMap.GetNextSetofEvents(sedaEvent.EventIndexInFlowMap);
                    foreach (var eventToRaise in nextEventSet)
                    {
                        var eventMessage = new SedaEvent(
                            sedaEvent.ResponseId,
                            EventType.Request,
                            currentCmsMessage.CMSMessageBody,
                            eventToRaise.EventName,
                            eventToRaise.Index
                            );
                        // Set the Event Status to Wait
                        await this._responseRepository.UpdateSpecificElementByFilterAsync(
                            x => x._id == sedaEvent.ResponseId && x.FlowMap.Events.Any(y => y.Index == eventToRaise.Index),
                            x => x.FlowMap.Events[-1].Status,
                            EventStatus.Wait);

                        await this._messagePublisher.PublishAsync(eventMessage);
                    }
                }
                break;

            case EventType.ResponseFailure:
                // update the DB status for the event
                await this._responseRepository.UpdateSpecificElementByFilterAsync(
                    x => x._id == sedaEvent.ResponseId && x.FlowMap.Events.Any(y => y.Index == sedaEvent.EventIndexInFlowMap),
                    x => x.FlowMap.Events[-1].Status,
                    EventStatus.Failure);

                // assumption: Abort the operation on the first failure. That is:
                // On first failure, update the operation status to Error
                // and send the FCM notification for complete with failure
                // TODO: If multiple parallel events are executing in a taskgroup,
                // the one or more events could fail and others could be successful
                // should not be sending multiple failure complete notifications in that case.
                // Get the response status, if it is not Error, then this is the first error
                // Update the response status to Error, if that is successful
                // raise the FCM notification for complete with failure
                var failResponseObj = await this._responseRepository.GetDocumentAsync(sedaEvent.ResponseId);

                if (failResponseObj.Status != EntityStatus.Error)
                {
                    failResponseObj.Status = EntityStatus.Error;
                    await this._responseRepository.ReplaceElementAsync(sedaEvent.ResponseId, failResponseObj);
                    await SendOperationCompleteNotificationAsync(failResponseObj);

                    break;
                }
                break;
            }
        }