public HandleContext(Aggregates.UnitOfWork.IDomain domain, Aggregates.UnitOfWork.IApplication app, IProcessor processor, IContainer container) { Domain = domain; App = app; Processor = processor; Container = container; }
public override async Task Invoke(IIncomingLogicalMessageContext context, Func <Task> next) { var container = Configuration.Settings.Container; // Child container with resolved domain and app uow used by downstream var child = container.GetChildContainer(); context.Extensions.Set(child); Configuration.Settings.LocalContainer.Value = child; // Only SEND messages deserve a UnitOfWork if (context.GetMessageIntent() != MessageIntentEnum.Send && context.GetMessageIntent() != MessageIntentEnum.Publish) { await next().ConfigureAwait(false); return; } if (context.Message.MessageType == typeof(Messages.Accept) || context.Message.MessageType == typeof(Messages.Reject)) { // If this happens the callback for the message took too long (likely due to a timeout) // normall NSB will report an exception for "No Handlers" - this will just log a warning and ignore Logger.WarnEvent("Overdue", "Overdue Accept/Reject {MessageType} callback - your timeouts might be too short", context.Message.MessageType.FullName); return; } var domainUOW = child.Resolve <Aggregates.UnitOfWork.IDomain>(); var delayed = child.Resolve <IDelayedChannel>(); Aggregates.UnitOfWork.IApplication appUOW = null; try { // IUnitOfWork might not be defined by user appUOW = child.Resolve <Aggregates.UnitOfWork.IApplication>(); appUOW.Bag = new System.Dynamic.ExpandoObject(); // if this is a retry pull the bag from the registry if (Bags.TryRemove(context.MessageId, out var bag)) { appUOW.Bag = bag; } } catch { // app uow doesn't have to be defined } // Set into the context because DI can be slow context.Extensions.Set(domainUOW); context.Extensions.Set(appUOW); var commitableUow = domainUOW as Aggregates.UnitOfWork.IUnitOfWork; var commitableAppUow = appUOW as Aggregates.UnitOfWork.IUnitOfWork; try { _metrics.Increment("Messages Concurrent", Unit.Message); using (_metrics.Begin("Message Duration")) { if (context.Message.Instance is Messages.ICommand) { await commitableUow.Begin().ConfigureAwait(false); } if (commitableAppUow != null) { await commitableAppUow.Begin().ConfigureAwait(false); } await delayed.Begin().ConfigureAwait(false); await next().ConfigureAwait(false); if (context.Message.Instance is Messages.ICommand) { await commitableUow.End().ConfigureAwait(false); } if (commitableAppUow != null) { await commitableAppUow.End().ConfigureAwait(false); } await delayed.End().ConfigureAwait(false); } } catch (Exception e) { Logger.WarnEvent("UOWException", e, "Received exception while processing message {MessageType}", context.Message.MessageType.FullName); _metrics.Mark("Message Errors", Unit.Errors); var trailingExceptions = new List <Exception>(); try { // Todo: if one throws an exception (again) the others wont work. Fix with a loop of some kind if (context.Message.Instance is Messages.ICommand) { await commitableUow.End(e).ConfigureAwait(false); } if (appUOW != null) { await commitableAppUow.End(e).ConfigureAwait(false); Bags.TryAdd(context.MessageId, appUOW.Bag); } await delayed.End(e).ConfigureAwait(false); } catch (Exception endException) { trailingExceptions.Add(endException); } if (trailingExceptions.Any()) { trailingExceptions.Insert(0, e); throw new AggregateException(trailingExceptions); } throw; } finally { child.Dispose(); _metrics.Decrement("Messages Concurrent", Unit.Message); context.Extensions.Remove <IContainer>(); } }