public async Task <IFullEvent[]> GetEvents(string stream, long?start = null, int?count = null) { // Don't worry about start or count - if stream is in cache its not being written to very often and start/count are unlikely to change var cached = _cache.Retreive(stream) as IFullEvent[]; if (cached != null) { return(cached); } var shard = Math.Abs(stream.GetHash() % _clients.Count()); var sliceStart = start ?? StreamPosition.Start; StreamEventsSlice current; var events = new List <ResolvedEvent>(); using (var ctx = _metrics.Begin("EventStore Read Time")) { do { var readsize = _readsize; if (count.HasValue) { readsize = Math.Min(count.Value - events.Count, _readsize); } current = await _clients[shard].ReadStreamEventsForwardAsync(stream, sliceStart, readsize, false) .ConfigureAwait(false); events.AddRange(current.Events); sliceStart = current.NextEventNumber; } while (!current.IsEndOfStream && (!count.HasValue || (events.Count != count.Value))); if (ctx.Elapsed > TimeSpan.FromSeconds(1)) { SlowLogger.InfoEvent("SlowRead", "{Events} events size {Size} stream [{Stream:l}] elapsed {Milliseconds} ms", events.Count, events.Sum(x => x.Event.Data.Length), stream, ctx.Elapsed.TotalMilliseconds); } Logger.DebugEvent("Read", "{Events} events size {Size} stream [{Stream:l}] elapsed {Milliseconds} ms", events.Count, events.Sum(x => x.Event.Data.Length), stream, ctx.Elapsed.TotalMilliseconds); } if (current.Status == SliceReadStatus.StreamNotFound) { throw new NotFoundException($"Stream [{stream}] does not exist on {_clients[shard].Settings.GossipSeeds[0].EndPoint.Address}!"); } var translatedEvents = events.Select(e => { var metadata = e.Event.Metadata; var data = e.Event.Data; var descriptor = _serializer.Deserialize <EventDescriptor>(metadata); if (descriptor.Compressed) { data = data.Decompress(); } var eventType = Type.GetType(e.Event.EventType, false); _mapper.Initialize(eventType); var @event = _serializer.Deserialize(eventType, data); // Special case if event was written without a version - substitue the position from store if (descriptor.Version == 0) { descriptor.Version = e.Event.EventNumber; } return((IFullEvent) new FullEvent { Descriptor = descriptor, Event = @event, EventId = e.Event.EventId }); }).ToArray(); _cache.Cache(stream, translatedEvents); return(translatedEvents); }
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>(); } }
public async Task <IFullEvent[]> GetEvents(string stream, long?start = null, int?count = null) { var shard = Math.Abs(stream.GetHashCode() % _clients.Count()); var sliceStart = start ?? StreamPosition.Start; StreamEventsSlice current; Logger.Write(LogLevel.Debug, () => $"Reading events from stream [{stream}] starting at {sliceStart}"); var events = new List <ResolvedEvent>(); using (var ctx = _metrics.Begin("EventStore Read Time")) { do { var readsize = _readsize; if (count.HasValue) { readsize = Math.Min(count.Value - events.Count, _readsize); } current = await _clients[shard].ReadStreamEventsForwardAsync(stream, sliceStart, readsize, false) .ConfigureAwait(false); Logger.Write(LogLevel.Debug, () => $"Read {current.Events.Length} events from position {sliceStart}. Status: {current.Status} LastEventNumber: {current.LastEventNumber} NextEventNumber: {current.NextEventNumber}"); events.AddRange(current.Events); sliceStart = current.NextEventNumber; } while (!current.IsEndOfStream && (!count.HasValue || (events.Count != count.Value))); if (ctx.Elapsed > TimeSpan.FromSeconds(1)) { SlowLogger.Write(LogLevel.Warn, () => $"Reading {events.Count} events of total size {events.Sum(x => x.Event.Data.Length)} from stream [{stream}] took {ctx.Elapsed.TotalSeconds} seconds!"); } Logger.Write(LogLevel.Info, () => $"Reading {events.Count} events of total size {events.Sum(x => x.Event.Data.Length)} from stream [{stream}] took {ctx.Elapsed.TotalMilliseconds} ms"); } Logger.Write(LogLevel.Debug, () => $"Finished reading {events.Count} events from stream [{stream}]"); if (current.Status == SliceReadStatus.StreamNotFound) { Logger.Write(LogLevel.Info, () => $"Stream [{stream}] does not exist!"); throw new NotFoundException($"Stream [{stream}] does not exist!"); } var translatedEvents = events.Select(e => { var metadata = e.Event.Metadata; var data = e.Event.Data; var descriptor = _serializer.Deserialize <EventDescriptor>(metadata); if (descriptor.Compressed) { data = data.Decompress(); } var @event = _serializer.Deserialize(e.Event.EventType, data); // Special case if event was written without a version - substitue the position from store if (descriptor.Version == 0) { descriptor.Version = e.Event.EventNumber; } return((IFullEvent) new FullEvent { Descriptor = descriptor, Event = @event, EventId = e.Event.EventId }); }).ToArray(); Logger.Write(LogLevel.Info, () => $"Read {translatedEvents.Length} events from stream [{stream}]"); return(translatedEvents); }
public async Task <IFullEvent[]> GetEvents(string stream, long?start = null, int?count = null) { var shard = Math.Abs(stream.GetHash() % _clients.Count()); var sliceStart = start ?? StreamPosition.Start; StreamEventsSlice current; var events = new List <ResolvedEvent>(); using (var ctx = _metrics.Begin("EventStore Read Time")) { do { var readsize = _readsize; if (count.HasValue) { readsize = Math.Min(count.Value - events.Count, _readsize); } current = await _clients[shard].ReadStreamEventsForwardAsync(stream, sliceStart, readsize, false) .ConfigureAwait(false); events.AddRange(current.Events); sliceStart = current.NextEventNumber; } while (!current.IsEndOfStream && (!count.HasValue || (events.Count != count.Value))); if (ctx.Elapsed > TimeSpan.FromSeconds(1)) { SlowLogger.InfoEvent("SlowRead", "{Events} events size {Size} stream [{Stream:l}] elapsed {Milliseconds} ms", events.Count, events.Sum(x => x.Event.Data.Length), stream, ctx.Elapsed.TotalMilliseconds); } Logger.DebugEvent("Read", "{Events} events size {Size} stream [{Stream:l}] elapsed {Milliseconds} ms", events.Count, events.Sum(x => x.Event.Data.Length), stream, ctx.Elapsed.TotalMilliseconds); } if (current.Status == SliceReadStatus.StreamNotFound) { throw new NotFoundException(stream, _clients[shard].Settings.GossipSeeds[0].EndPoint.Address); } var translatedEvents = events.Select(e => { var metadata = e.Event.Metadata; var data = e.Event.Data; var descriptor = _serializer.Deserialize <EventDescriptor>(metadata); if (descriptor == null || descriptor.EventId == Guid.Empty) { // Assume we read from a children projection // (theres no way to set metadata in projection states) var children = _serializer.Deserialize <ChildrenProjection>(data); if (!(children is IEvent)) { throw new UnknownMessageException(e.Event.EventType); } return(new FullEvent { Descriptor = null, Event = children as IEvent, EventId = Guid.Empty }); } if (descriptor.Compressed) { data = data.Decompress(); } var eventType = _registrar.GetNamedType(e.Event.EventType); _mapper.Initialize(eventType); var @event = _serializer.Deserialize(eventType, data); if (!(@event is IEvent)) { throw new UnknownMessageException(e.Event.EventType); } // Special case if event was written without a version - substitue the position from store if (descriptor.Version == 0) { descriptor.Version = e.Event.EventNumber; } return((IFullEvent) new FullEvent { Descriptor = descriptor, Event = @event as IEvent, EventId = e.Event.EventId }); }).ToArray(); return(translatedEvents); }
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); // Only SEND messages deserve a UnitOfWork if (context.MessageHeaders[Headers.MessageIntent] != MessageIntentEnum.Send.ToString() && context.MessageHeaders[Headers.MessageIntent] != MessageIntentEnum.Publish.ToString()) { 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.Write(LogLevel.Warn, $"Received overdue {context.Message.MessageType.Name} callback - your timeouts might be too short"); return; } var domainUOW = child.Resolve <IDomainUnitOfWork>(); var delayed = child.Resolve <IDelayedChannel>(); IUnitOfWork appUOW = null; try { // IUnitOfWork might not be defined by user appUOW = child.Resolve <IUnitOfWork>(); } catch { } // Set into the context because DI can be slow context.Extensions.Set(domainUOW); context.Extensions.Set(appUOW); Logger.Write(LogLevel.Debug, () => $"Starting UOW for message {context.MessageId} type {context.Message.MessageType.FullName}"); try { _metrics.Increment("Messages Concurrent", Unit.Message); using (_metrics.Begin("Message Duration")) { Logger.Write(LogLevel.Debug, () => $"Running UOW.Begin for message {context.MessageId}"); await domainUOW.Begin().ConfigureAwait(false); if (appUOW != null) { await appUOW.Begin().ConfigureAwait(false); } await delayed.Begin().ConfigureAwait(false); await next().ConfigureAwait(false); Logger.Write(LogLevel.Debug, () => $"Running UOW.End for message {context.MessageId}"); await domainUOW.End().ConfigureAwait(false); if (appUOW != null) { await appUOW.End().ConfigureAwait(false); } await delayed.End().ConfigureAwait(false); } } catch (Exception e) { Logger.Info($"Caught exception '{e.GetType().FullName}' while executing message {context.MessageId} {context.Message.MessageType.FullName}", e); _metrics.Mark("Message Errors", Unit.Errors); var trailingExceptions = new List <Exception>(); try { Logger.Write(LogLevel.Debug, () => $"Running UOW.End with exception [{e.GetType().Name}] for message {context.MessageId}"); // Todo: if one throws an exception (again) the others wont work. Fix with a loop of some kind await domainUOW.End(e).ConfigureAwait(false); if (appUOW != null) { await appUOW.End(e).ConfigureAwait(false); } await delayed.End(e).ConfigureAwait(false); } catch (Exception endException) { trailingExceptions.Add(endException); } if (trailingExceptions.Any()) { trailingExceptions.Insert(0, e); throw new System.AggregateException(trailingExceptions); } throw; } finally { child.Dispose(); _metrics.Decrement("Messages Concurrent", Unit.Message); context.Extensions.Remove <IContainer>(); } }