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)); }
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)); }
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(); }