예제 #1
0
        /// <inheritdoc />
        public async Task Save <T>(T es)
            where T : class, TEventSourced
        {
            if (es == null)
            {
                return;
            }

            var events = es.GetUncommittedEvents().ToList();

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

            var stream = await _streams.Find <T>(es.Id, _timeline.Id) ?? _streams.CreateEmpty(es, _timeline.Id); // _streams.GetOrAdd(es, _timeline.Id);

            if (stream.Version >= 0 && es.Version - events.Count < stream.Version)
            {
                throw new InvalidOperationException($"Stream ( {stream.Key}@{stream.Version} ) is ahead of aggregate root with version {es.Version - events.Count} saving {events.Count} events )");
            }

            foreach (var e in events.Cast <Event>())
            {
                if (e.Timestamp == default)
                {
                    e.Timestamp = _timeline.Now;
                }
                if (e.LocalId == default)
                {
                    e.LocalId = new EventId(Configuration.ReplicaName, e.Timestamp);
                }
                if (e.OriginId == default)
                {
                    e.OriginId = e.LocalId;
                }
                e.Stream   = stream.Key;
                e.Timeline = _timeline.Id;
            }

            await _eventStore.AppendToStream(stream, events);

            if (es is ISaga saga)
            {
                var commands = saga.GetUncommittedCommands();
                foreach (var command in commands)
                {
                    await _bus.CommandAsync(command);
                }
            }
#if USE_ES_CACHE
            _cache[stream.Key] = es;
#endif
        }
예제 #2
0
        public async Task <T> Find <T>(Guid id) where T : class, IEventSourced, new()
        {
            var stream = _streams.Find(id);

            if (stream == null)
            {
                return(null);
            }

            var events = await _eventStore.ReadStream(stream, 0, int.MaxValue);

            var aggregate = new T();

            aggregate.LoadFrom <T>(id, events);

            return(aggregate);
        }
예제 #3
0
            public MergeFlow(ITimeline currentBranch, IEventStore <T> eventStore, IStreamLocator streamLocator, bool doMerge)
                : base(Configuration.DataflowOptions)
            {
                _inputBlock = new ActionBlock <IStream>(
                    async s =>
                {
                    var version      = ExpectedVersion.EmptyStream;
                    var parentStream = s.Branch(currentBranch?.Id, ExpectedVersion.EmptyStream);
                    var parent       = s.Parent;
                    while (parent != null && parent.Version > ExpectedVersion.EmptyStream)
                    {
                        parentStream = await streamLocator.Find(parent);
                        version      = parentStream.Version;

                        if (currentBranch != null &&
                            (version > parent.Version && parent.Timeline == currentBranch.Id))
                        {
                            var theseEvents = await eventStore
                                              .ReadStream <IEvent>(parentStream, parent.Version + 1, version - parent.Version)
                                              .Select(e => e.MessageId).ToList();
                            var thoseEvents = await eventStore
                                              .ReadStream <IEvent>(s, parent.Version + 1, version - parent.Version)
                                              .Select(e => e.MessageId).ToList();
                            if (theseEvents.Zip(thoseEvents, (e1, e2) => (e1, e2)).Any(x => x.Item1 != x.Item2))
                            {
                                throw new InvalidOperationException(
                                    $"{currentBranch?.Id} timeline has moved on in the meantime, aborting...( {parentStream.Key} : {version} > {parent.Version} )");
                            }

                            return;
                        }

                        if (s.Version == version)
                        {
                            return;
                        }

                        if (parentStream.Timeline == currentBranch?.Id)
                        {
                            break;
                        }

                        parent = parent.Parent;
                    }

                    if (!doMerge)
                    {
                        return;
                    }

                    Interlocked.Increment(ref _numberOfStreams);

                    var events = await eventStore.ReadStream <IEvent>(s, version + 1, s.Version - version).ToList();
                    foreach (var e in events.OfType <Event>())
                    {
                        e.Stream = parentStream.Key;
                    }

                    Interlocked.Add(ref _numberOfEvents, events.Count);

                    await eventStore.AppendToStream(parentStream, events, false);
                }, Configuration.DataflowOptions.ToDataflowBlockOptions(true));     // .ToExecutionBlockOption(true));

                RegisterChild(_inputBlock);
            }