Beispiel #1
0
        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>();
            }
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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>();
            }
        }