예제 #1
0
        public async Task Should_insert_and_retrieve_parallel()
        {
            var expectedEvents = 10 * 1000;

            var consumer      = new MyEventConsumer(expectedEvents);
            var consumerGrain = new MyEventConsumerGrain(_ => consumer, grainState, _.EventStore, eventDataFormatter, log);

            await consumerGrain.ActivateAsync(consumer.Name);

            await consumerGrain.ActivateAsync();

            Parallel.For(0, 20, x =>
            {
                for (var i = 0; i < 500; i++)
                {
                    var commitId = Guid.NewGuid();

                    var data = eventDataFormatter.ToEventData(Envelope.Create <IEvent>(new MyEvent()), commitId);

                    _.EventStore.AppendAsync(commitId, commitId.ToString(), new[] { data }).Wait();
                }
            });

            await AssertConsumerAsync(expectedEvents, consumer);
        }
예제 #2
0
        private async Task HandleEventAsync(IBackupReader reader, IEnumerable <IBackupHandler> handlers, string stream, Envelope <IEvent> @event)
        {
            if (@event.Payload is AppCreated appCreated)
            {
                if (!string.IsNullOrWhiteSpace(CurrentJob.NewAppName))
                {
                    appCreated.Name = CurrentJob.NewAppName;

                    CurrentJob.AppId = NamedId.Of(appCreated.AppId.Id, CurrentJob.NewAppName);
                }
                else
                {
                    CurrentJob.AppId = appCreated.AppId;
                }

                await CreateContextAsync(reader);
            }

            if (@event.Payload is SquidexEvent squidexEvent && squidexEvent.Actor != null)
            {
                if (restoreContext.UserMapping.TryMap(squidexEvent.Actor, out var newUser))
                {
                    squidexEvent.Actor = newUser;
                }
            }

            if (@event.Payload is AppEvent appEvent)
            {
                appEvent.AppId = CurrentJob.AppId;
            }

            foreach (var handler in handlers)
            {
                if (!await handler.RestoreEventAsync(@event, restoreContext))
                {
                    return;
                }
            }

            var eventData   = eventDataFormatter.ToEventData(@event, @event.Headers.CommitId());
            var eventCommit = new List <EventData> {
                eventData
            };

            await eventStore.AppendAsync(Guid.NewGuid(), stream, eventCommit);

            Log($"Read {reader.ReadEvents} events and {reader.ReadAttachments} attachments.", true);
        }
예제 #3
0
        private async Task ReadEventsAsync(BackupReader reader)
        {
            await reader.ReadEventsAsync(streamNameResolver, async (storedEvent) =>
            {
                var @event = eventDataFormatter.Parse(storedEvent.Data);

                if (@event.Payload is SquidexEvent squidexEvent)
                {
                    squidexEvent.Actor = actor;
                }

                if (@event.Payload is AppCreated appCreated)
                {
                    CurrentJob.AppId = appCreated.AppId.Id;

                    if (!string.IsNullOrWhiteSpace(CurrentJob.NewAppName))
                    {
                        appCreated.Name = CurrentJob.NewAppName;
                    }
                }

                if (@event.Payload is AppEvent appEvent && !string.IsNullOrWhiteSpace(CurrentJob.NewAppName))
                {
                    appEvent.AppId = new NamedId <Guid>(appEvent.AppId.Id, CurrentJob.NewAppName);
                }

                foreach (var handler in handlers)
                {
                    await handler.RestoreEventAsync(@event, CurrentJob.AppId, reader, actor);
                }

                var eventData   = eventDataFormatter.ToEventData(@event, @event.Headers.CommitId());
                var eventCommit = new List <EventData> {
                    eventData
                };

                await eventStore.AppendAsync(Guid.NewGuid(), storedEvent.StreamName, eventCommit);

                Log($"Read {reader.ReadEvents} events and {reader.ReadAttachments} attachments.", true);
            });

            Log("Reading events completed.");
        }
예제 #4
0
        private async Task <object> Upsert <TCommand>(TCommand command, Func <TCommand, object> handler) where TCommand : CommentsCommand
        {
            Guard.NotNull(command);
            Guard.NotNull(handler);

            if (command.ExpectedVersion > EtagVersion.Any && command.ExpectedVersion != Version)
            {
                throw new DomainObjectVersionException(Key, GetType(), Version, command.ExpectedVersion);
            }

            var prevVersion = version;

            try
            {
                var result = handler(command);

                if (uncommittedEvents.Count > 0)
                {
                    var commitId = Guid.NewGuid();

                    var eventData = uncommittedEvents.Select(x => eventDataFormatter.ToEventData(x, commitId)).ToList();

                    await eventStore.AppendAsync(commitId, streamName, prevVersion, eventData);
                }

                events.AddRange(uncommittedEvents);

                return(result);
            }
            catch
            {
                version = prevVersion;

                throw;
            }
            finally
            {
                uncommittedEvents.Clear();
            }
        }
예제 #5
0
        private async Task HandleEventAsync(BackupReader reader, string stream, Envelope <IEvent> @event)
        {
            if (@event.Payload is SquidexEvent squidexEvent)
            {
                squidexEvent.Actor = actor;
            }

            if (@event.Payload is AppCreated appCreated)
            {
                CurrentJob.AppId = appCreated.AppId.Id;

                if (!string.IsNullOrWhiteSpace(CurrentJob.NewAppName))
                {
                    appCreated.Name = CurrentJob.NewAppName;
                }
            }

            if (@event.Payload is AppEvent appEvent && !string.IsNullOrWhiteSpace(CurrentJob.NewAppName))
            {
                appEvent.AppId = new NamedId <Guid>(appEvent.AppId.Id, CurrentJob.NewAppName);
            }

            foreach (var handler in handlers)
            {
                if (!await handler.RestoreEventAsync(@event, CurrentJob.AppId, reader, actor))
                {
                    return;
                }
            }

            var eventData   = eventDataFormatter.ToEventData(@event, @event.Headers.CommitId());
            var eventCommit = new List <EventData> {
                eventData
            };

            await eventStore.AppendAsync(Guid.NewGuid(), stream, eventCommit);

            Log($"Read {reader.ReadEvents} events and {reader.ReadAttachments} attachments.", true);
        }
예제 #6
0
 private EventData[] GetEventData(Envelope <IEvent>[] events, Guid commitId)
 {
     return(events.Map(x => eventDataFormatter.ToEventData(x, commitId, true)));
 }
예제 #7
0
        public async Task Should_write_and_read_events_to_backup(BackupVersion version)
        {
            var randomGenerator = new Random();
            var randomDomainIds = new List <DomainId>();

            for (var i = 0; i < 100; i++)
            {
                randomDomainIds.Add(DomainId.NewGuid());
            }

            DomainId RandomDomainId()
            {
                return(randomDomainIds[randomGenerator.Next(randomDomainIds.Count)]);
            }

            var sourceEvents = new List <(string Stream, Envelope <MyEvent> Event)>();

            for (var i = 0; i < 200; i++)
            {
                var @event = new MyEvent();

                var envelope = Envelope.Create(@event);

                envelope.Headers.Add("Id", JsonValue.Create(@event.Id));
                envelope.Headers.Add("Index", JsonValue.Create(i));

                sourceEvents.Add(($"My-{RandomDomainId()}", envelope));
            }

            await TestReaderWriterAsync(version, async writer =>
            {
                foreach (var(stream, envelope) in sourceEvents)
                {
                    var eventData   = formatter.ToEventData(envelope, Guid.NewGuid(), true);
                    var eventStored = new StoredEvent(stream, "1", 2, eventData);

                    var index = int.Parse(envelope.Headers["Index"].ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture);

                    if (index % 17 == 0)
                    {
                        await WriteGuidAsync(writer, index.ToString(CultureInfo.InvariantCulture), envelope.Payload.Id);
                    }
                    else if (index % 37 == 0)
                    {
                        await WriteJsonGuidAsync(writer, index.ToString(CultureInfo.InvariantCulture), envelope.Payload.Id);
                    }

                    writer.WriteEvent(eventStored);
                }
            }, async reader =>
            {
                var targetEvents = new List <(string Stream, Envelope <IEvent> Event)>();

                await foreach (var @event in reader.ReadEventsAsync(streamNameResolver, formatter))
                {
                    var index = int.Parse(@event.Event.Headers["Index"].ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture);

                    var id = Guid.Parse(@event.Event.Headers["Id"].ToString());

                    if (index % 17 == 0)
                    {
                        var guid = await ReadGuidAsync(reader, index.ToString(CultureInfo.InvariantCulture));

                        Assert.Equal(id, guid);
                    }
                    else if (index % 37 == 0)
                    {
                        var guid = await ReadJsonGuidAsync(reader, index.ToString(CultureInfo.InvariantCulture));

                        Assert.Equal(id, guid);
                    }

                    targetEvents.Add(@event);
                }

                for (var i = 0; i < targetEvents.Count; i++)
                {
                    var targetEvent  = targetEvents[i].Event.To <MyEvent>();
                    var targetStream = targetEvents[i].Stream;

                    var sourceEvent  = sourceEvents[i].Event.To <MyEvent>();
                    var sourceStream = sourceEvents[i].Stream;

                    Assert.Equal(sourceEvent.Payload.Id, targetEvent.Payload.Id);
                    Assert.Equal(sourceStream, targetStream);
                }
            });
        }
예제 #8
0
        public async Task Should_write_and_read_events_to_backup(BackupVersion version)
        {
            var stream = new MemoryStream();

            var random      = new Random();
            var randomGuids = new List <Guid>();

            for (var i = 0; i < 100; i++)
            {
                randomGuids.Add(Guid.NewGuid());
            }

            Guid RandomGuid()
            {
                return(randomGuids[random.Next(randomGuids.Count)]);
            }

            var sourceEvents = new List <(string Stream, Envelope <IEvent> Event)>();

            for (var i = 0; i < 200; i++)
            {
                var @event = new MyEvent
                {
                    GuidNamed = NamedId.Of(RandomGuid(), $"name{i}"),
                    GuidRaw   = RandomGuid(),
                    Values    = new Dictionary <Guid, string>
                    {
                        [RandomGuid()] = "Key"
                    }
                };

                var envelope = Envelope.Create <IEvent>(@event);

                envelope.Headers.Add(RandomGuid().ToString(), i);
                envelope.Headers.Add("Id", RandomGuid().ToString());
                envelope.Headers.Add("Index", i);

                sourceEvents.Add(($"My-{RandomGuid()}", envelope));
            }

            using (var writer = new BackupWriter(serializer, stream, true, version))
            {
                foreach (var(_, envelope) in sourceEvents)
                {
                    var eventData   = formatter.ToEventData(envelope, Guid.NewGuid(), true);
                    var eventStored = new StoredEvent("S", "1", 2, eventData);

                    var index = int.Parse(envelope.Headers["Index"].ToString());

                    if (index % 17 == 0)
                    {
                        await writer.WriteBlobAsync(index.ToString(), innerStream =>
                        {
                            innerStream.WriteByte((byte)index);

                            return(TaskHelper.Done);
                        });
                    }
                    else if (index % 37 == 0)
                    {
                        await writer.WriteJsonAsync(index.ToString(), $"JSON_{index}");
                    }

                    writer.WriteEvent(eventStored);
                }
            }

            stream.Position = 0;

            var targetEvents = new List <(string Stream, Envelope <IEvent> Event)>();

            using (var reader = new BackupReader(serializer, stream))
            {
                await reader.ReadEventsAsync(streamNameResolver, formatter, async @event =>
                {
                    var index = int.Parse(@event.Event.Headers["Index"].ToString());

                    if (index % 17 == 0)
                    {
                        await reader.ReadBlobAsync(index.ToString(), innerStream =>
                        {
                            var byteRead = innerStream.ReadByte();

                            Assert.Equal((byte)index, byteRead);

                            return(TaskHelper.Done);
                        });
                    }
                    else if (index % 37 == 0)
                    {
                        var json = await reader.ReadJsonAttachmentAsync <string>(index.ToString());

                        Assert.Equal($"JSON_{index}", json);
                    }

                    targetEvents.Add(@event);
                });

                void CompareGuid(Guid source, Guid target)
                {
                    Assert.Equal(source, reader.OldGuid(target));
                    Assert.NotEqual(source, target);
                }

                for (var i = 0; i < targetEvents.Count; i++)
                {
                    var target = targetEvents[i].Event.To <MyEvent>();

                    var source = sourceEvents[i].Event.To <MyEvent>();

                    CompareGuid(source.Payload.Values.First().Key, target.Payload.Values.First().Key);
                    CompareGuid(source.Payload.GuidRaw, target.Payload.GuidRaw);
                    CompareGuid(source.Payload.GuidNamed.Id, target.Payload.GuidNamed.Id);
                    CompareGuid(source.Headers.GetGuid("Id"), target.Headers.GetGuid("Id"));

                    Assert.Equal(Guid.Empty, target.Payload.GuidEmpty);
                }
            }
        }
예제 #9
0
        private async Task HandleEventAsync(IBackupReader reader, IEnumerable <IBackupHandler> handlers, string stream, Envelope <IEvent> @event)
        {
            if (@event.Payload is AppCreated appCreated)
            {
                var previousAppId = appCreated.AppId.Id;

                if (!string.IsNullOrWhiteSpace(CurrentJob.NewAppName))
                {
                    appCreated.Name = CurrentJob.NewAppName;

                    CurrentJob.AppId = NamedId.Of(DomainId.NewGuid(), CurrentJob.NewAppName);
                }
                else
                {
                    CurrentJob.AppId = NamedId.Of(DomainId.NewGuid(), appCreated.Name);
                }

                await CreateContextAsync(reader, previousAppId);
            }

            stream = stream.Replace(
                restoreContext.PreviousAppId.ToString(),
                restoreContext.AppId.ToString());

            if (@event.Payload is SquidexEvent squidexEvent && squidexEvent.Actor != null)
            {
                if (restoreContext.UserMapping.TryMap(squidexEvent.Actor, out var newUser))
                {
                    squidexEvent.Actor = newUser;
                }
            }

            if (@event.Payload is AppEvent appEvent)
            {
                appEvent.AppId = CurrentJob.AppId;
            }

            if (@event.Headers.TryGet(CommonHeaders.AggregateId, out var aggregateId) && aggregateId is JsonString s)
            {
                var id = s.Value.Replace(
                    restoreContext.PreviousAppId.ToString(),
                    restoreContext.AppId.ToString());

                var domainId = DomainId.Create(id);

                @event.SetAggregateId(domainId);
            }

            foreach (var handler in handlers)
            {
                if (!await handler.RestoreEventAsync(@event, restoreContext))
                {
                    return;
                }
            }

            var eventData = eventDataFormatter.ToEventData(@event, @event.Headers.CommitId());

            var eventCommit = new List <EventData>
            {
                eventData
            };

            await eventStore.AppendAsync(Guid.NewGuid(), stream, eventCommit);

            Log($"Read {reader.ReadEvents} events and {reader.ReadAttachments} attachments.", true);
        }
예제 #10
0
 private EventData[] GetEventData(Envelope <IEvent>[] events, Guid commitId)
 {
     return(@events.Select(x => eventDataFormatter.ToEventData(x, commitId, true)).ToArray());
 }