Ejemplo n.º 1
0
        public Task <TResponse> Process <TService, TResponse>(TService service, IContainer container) where TService : IService <TResponse>
        {
            var handlerType = typeof(IProvideService <,>).MakeGenericType(typeof(TService), typeof(TResponse));

            var handlerFunc = (Func <object, TService, IServiceContext, Task <TResponse> >)Processors.GetOrAdd(handlerType, t => ReflectionExtensions.MakeServiceHandler <TService, TResponse>(handlerType));
            var handler     = container.Resolve(handlerType);

            if (handler == null)
            {
                Logger.ErrorEvent("ProcessFailure", "No handler [{ServiceType:l}] response [{Response:l}]", typeof(TService).FullName, typeof(TResponse).FullName);
                return(Task.FromResult(default(TResponse)));
            }

            // Todo: both units of work should come from the pipeline not the container
            var context = new HandleContext(container.Resolve <Aggregates.UnitOfWork.IDomain>(), container.Resolve <Aggregates.UnitOfWork.IApplication>(), container.Resolve <IProcessor>(), container);

            return(handlerFunc(handler, service, context));
        }
Ejemplo n.º 2
0
        public Task <TResponse> Process <TQuery, TResponse>(TQuery query, IContainer container) where TQuery : IQuery <TResponse>
        {
            var handlerType = typeof(IHandleQueries <,>).MakeGenericType(typeof(TQuery), typeof(TResponse));

            var handlerFunc = (Func <object, TQuery, IHandleContext, Task <TResponse> >)Processors.GetOrAdd(handlerType, t => ReflectionExtensions.MakeQueryHandler <TQuery, TResponse>(handlerType));
            var handler     = container.Resolve(handlerType);

            if (handler == null)
            {
                Logger.ErrorEvent("ProcessFailure", "No handler [{QueryType:l}] response [{Response:l}]", typeof(TQuery).FullName, typeof(TResponse).FullName);
                return(null);
            }

            // Todo: both units of work should come from the pipeline not the container
            var context = new HandleContext(container.Resolve <IDomainUnitOfWork>(), container.Resolve <IUnitOfWork>(), container);

            return(handlerFunc(handler, query, context));
        }
Ejemplo n.º 3
0
        public void Invoke(IncomingContext context, Action next)
        {
            ActiveSagaInstance saga;

            if (context.TryGet(out saga) && saga.NotFound && saga.SagaType == context.MessageHandler.Instance.GetType())
            {
                next();
                return;
            }

            var messageHandler = context.Get <AsyncMessageHandler>();

            //var handleContext = new HandleContext { Bus = Bus, Context = context };
            //messageHandler.Invocation(messageHandler.Handler, context.IncomingLogicalMessage.Instance, handleContext).Wait();
            Task.Run((Func <Task>)(async() =>
            {
                var handleContext = new HandleContext {
                    Bus = Bus, Context = context
                };
                await messageHandler.Invocation(messageHandler.Handler, context.IncomingLogicalMessage.Instance, handleContext);
            })).Wait();

            next();
        }
        // Todo: all the logging and timing can be moved into a "Debug Dispatcher" which can be registered as the IDispatcher if the user wants
        private async Task Process(Object @event, IEventDescriptor descriptor = null, long?position = null)
        {
            var       eventType = _mapper.GetMappedTypeFor(@event.GetType());
            Stopwatch s         = null;

            var handleContext = new HandleContext
            {
                Bus             = _bus,
                EventDescriptor = descriptor
            };

            using (_eventsTimer.NewContext())
            {
                if (Logger.IsDebugEnabled)
                {
                    Logger.DebugFormat("Processing event {0} at position {1}.  Size of queue: {2}/{3}", eventType.FullName, position, _processingQueueSize, _maxQueueSize);
                }


                using (var childBuilder = _builder.CreateChildBuilder())
                {
                    var            handlerGenericType = typeof(IHandleMessagesAsync <>).MakeGenericType(eventType);
                    List <dynamic> handlers           = childBuilder.BuildAll(handlerGenericType).ToList();

                    if (handlers.Count == 0)
                    {
                        return;
                    }

                    var success = false;
                    var retry   = 0;
                    do
                    {
                        var uows = new ConcurrentStack <IEventUnitOfWork>();

                        var mutators = childBuilder.BuildAll <IEventMutator>();

                        if (Logger.IsDebugEnabled)
                        {
                            s = Stopwatch.StartNew();
                        }
                        if (mutators != null && mutators.Any())
                        {
                            Parallel.ForEach(mutators, _parallelOptions, mutate =>
                            {
                                //if (Logger.IsDebugEnabled)
                                Logger.DebugFormat("Mutating incoming event {0} with mutator {1}", eventType.FullName, mutate.GetType().FullName);
                                @event = mutate.MutateIncoming(@event, descriptor, position);
                            });
                        }

                        await childBuilder.BuildAll <IEventUnitOfWork>().ForEachAsync(2, async(uow) =>
                        {
                            uows.Push(uow);
                            uow.Builder = childBuilder;
                            await uow.Begin();
                        });

                        if (Logger.IsDebugEnabled)
                        {
                            s.Stop();
                            Logger.DebugFormat("UOW.Begin for event {0} took {1} ms", eventType.FullName, s.ElapsedMilliseconds);
                        }
                        try
                        {
                            if (Logger.IsDebugEnabled)
                            {
                                s.Restart();
                            }

                            Func <dynamic, Task> processor = async(handler) =>
                            {
                                using (_handlerTimer.NewContext())
                                {
                                    var handlerRetries = 0;
                                    var handlerSuccess = false;
                                    do
                                    {
                                        try
                                        {
                                            Stopwatch handlerWatch = null;
                                            if (Logger.IsDebugEnabled)
                                            {
                                                Logger.DebugFormat("Executing event {0} on handler {1}", eventType.FullName, handler.GetType().FullName);
                                                handlerWatch = Stopwatch.StartNew();
                                            }
                                            var lambda = _objectInvoker.Invoker(handler, eventType);

                                            await lambda(handler, @event, handleContext);

                                            if (Logger.IsDebugEnabled)
                                            {
                                                handlerWatch.Stop();
                                                Logger.DebugFormat("Executing event {0} on handler {1} took {2} ms", eventType.FullName, handler.GetType().FullName, handlerWatch.ElapsedMilliseconds);
                                            }
                                            handlerSuccess = true;
                                        }
                                        catch (RetryException e)
                                        {
                                            Logger.InfoFormat("Received retry signal while dispatching event {0} to {1}. Retry: {2}/3\nException: {3}", eventType.FullName, handler.FullName, handlerRetries, e);
                                            handlerRetries++;
                                        }
                                    } while (!handlerSuccess && (_maxRetries == -1 || handlerRetries <= _maxRetries));

                                    if (!handlerSuccess)
                                    {
                                        Logger.ErrorFormat("Failed executing event {0} on handler {1}", eventType.FullName, handler.FullName);
                                        throw new RetryException(String.Format("Failed executing event {0} on handler {1}", eventType.FullName, handler.FullName));
                                    }
                                }
                            };

                            // Run each handler in parallel (or not) (if handler ever is ASYNC can't use Parallel)
                            if (_parallelHandlers)
                            {
                                await handlers.ForEachAsync(_parallelOptions.MaxDegreeOfParallelism, processor);
                            }
                            else
                            {
                                foreach (var handler in handlers)
                                {
                                    await processor(handler);
                                }
                            }

                            if (Logger.IsDebugEnabled)
                            {
                                s.Stop();
                                Logger.DebugFormat("Processing event {0} took {1} ms", eventType.FullName, s.ElapsedMilliseconds);
                            }
                        }
                        catch (Exception e)
                        {
                            var trailingExceptions = new ConcurrentBag <Exception>();
                            await uows.Generate().ForEachAsync(2, async(uow) =>
                            {
                                try
                                {
                                    await uow.End(e);
                                }
                                catch (Exception endException)
                                {
                                    trailingExceptions.Add(endException);
                                }
                            });

                            if (trailingExceptions.Any())
                            {
                                var exceptions = trailingExceptions.ToList();
                                exceptions.Insert(0, e);
                                e = new System.AggregateException(exceptions);
                            }

                            // Only log if the event has failed more than half max retries indicating a possible non-transient error
                            if (retry > (_maxRetries / 2))
                            {
                                Logger.InfoFormat("Encountered an error while processing {0}. Retry {1}/{2}\nPayload: {3}\nException details:\n{4}", eventType.FullName, retry, _maxRetries, JsonConvert.SerializeObject(@event), e);
                            }
                            else
                            {
                                Logger.DebugFormat("Encountered an error while processing {0}. Retry {1}/{2}\nPayload: {3}\nException details:\n{4}", eventType.FullName, retry, _maxRetries, JsonConvert.SerializeObject(@event), e);
                            }

                            _errorsMeter.Mark();
                            retry++;
                            Thread.Sleep(10);
                            continue;
                        }


                        // Failures when executing UOW.End `could` be transient (network or disk hicup)
                        // A failure of 1 uow in a chain of 5 is a problem as it could create a mangled DB (partial update via one uow then crash)
                        // So we'll just keep retrying the failing UOW forever until it succeeds.
                        if (Logger.IsDebugEnabled)
                        {
                            s.Restart();
                        }
                        var endSuccess = false;
                        var endRetry   = 0;
                        while (!endSuccess)
                        {
                            try
                            {
                                await uows.Generate().ForEachAsync(2, async(uow) =>
                                {
                                    try
                                    {
                                        await uow.End();
                                    }
                                    catch
                                    {
                                        // If it failed it needs to go back on the stack
                                        uows.Push(uow);
                                        throw;
                                    }
                                });

                                endSuccess = true;
                            }
                            catch (Exception e)
                            {
                                if (endRetry > (_maxRetries / 2))
                                {
                                    Logger.ErrorFormat("UOW.End failure while processing event {0} - retry {1}/{3}\nException:\n{2}", eventType.FullName, retry, e, _maxRetries);
                                }
                                else
                                {
                                    Logger.DebugFormat("UOW.End failure while processing event {0} - retry {1}/{3}\nException:\n{2}", eventType.FullName, retry, e, _maxRetries);
                                }
                                endRetry++;
                                Thread.Sleep(50);
                            }
                        }
                        if (Logger.IsDebugEnabled)
                        {
                            s.Stop();
                            Logger.DebugFormat("UOW.End for event {0} took {1} ms", eventType.FullName, s.ElapsedMilliseconds);
                        }
                        success = true;
                    } while (!success && (_maxRetries == -1 || retry < _maxRetries));

                    if (!success)
                    {
                        var message = String.Format("Encountered an error while processing {0}.  Ran out of retries, dropping event.\nPayload: {3}", eventType.FullName, JsonConvert.SerializeObject(@event));
                        if (_dropEventFatal)
                        {
                            Logger.Fatal(message);
                            throw new SubscriptionCanceled(message);
                        }

                        Logger.Error(message);
                    }
                }
            }
            _eventsMeter.Mark();
        }