コード例 #1
0
        private async Task SaveChanges <T>(
            EventStoreDbContext context,
            Guid sourceId,
            CancellationToken cancellationToken)
            where T : class, IEventSourced
        {
            try
            {
                await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
            }
            catch (DbUpdateException exception)
                when(exception.InnerException is UpdateException)
                {
                    var updateException = (UpdateException)exception.InnerException;

                    Correlation correlation = updateException
                                              .StateEntries
                                              .Select(s => s.Entity)
                                              .OfType <Correlation>()
                                              .FirstOrDefault();

                    if (correlation != null)
                    {
                        throw new DuplicateCorrelationException(
                                  typeof(T),
                                  sourceId,
                                  correlation.CorrelationId,
                                  exception);
                    }

                    throw;
                }
        }
コード例 #2
0
        private async Task PublishEvents(
            Guid sourceId,
            CancellationToken cancellationToken)
        {
            using (EventStoreDbContext context = _dbContextFactory.Invoke())
            {
                List <PendingEvent> pendingEvents = await context
                                                    .PendingEvents
                                                    .Where(e => e.AggregateId == sourceId)
                                                    .OrderBy(e => e.Version)
                                                    .ToListAsync(cancellationToken)
                                                    .ConfigureAwait(false);

                List <Envelope> envelopes = pendingEvents
                                            .Select(e => RestoreEnvelope(e))
                                            .ToList();

                if (envelopes.Any() == false)
                {
                    return;
                }

                await _messageBus.SendBatch(envelopes, cancellationToken).ConfigureAwait(false);

                context.PendingEvents.RemoveRange(pendingEvents);

                await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
            }
        }
コード例 #3
0
        private async Task SaveChanges <T>(
            EventStoreDbContext context,
            Guid sourceId,
            Guid?correlationId,
            CancellationToken cancellationToken)
            where T : class, IEventSourced
        {
            try
            {
                using (IDbContextTransaction transaction = await
                                                           context.Database.BeginTransactionAsync(cancellationToken).ConfigureAwait(false))
                {
                    await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);

                    transaction.Commit();
                }
            }
            catch (DbUpdateException exception) when(correlationId.HasValue)
            {
                IQueryable <Correlation> query = from c in context.Correlations
                                                 where c.AggregateId == sourceId && c.CorrelationId == correlationId
                                                 select c;

                if (await query.AnyAsync().ConfigureAwait(false))
                {
                    throw new DuplicateCorrelationException(
                              typeof(T),
                              sourceId,
                              correlationId.Value,
                              exception);
                }

                throw;
            }
        }
コード例 #4
0
 private static async Task RemoveEvents(
     EventStoreDbContext context,
     List <PendingEvent> pendingEvents,
     CancellationToken cancellationToken)
 {
     foreach (PendingEvent pendingEvent in pendingEvents)
     {
         try
         {
             context.PendingEvents.Remove(pendingEvent);
             await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
         }
         catch (DbUpdateConcurrencyException)
         {
             context.Entry(pendingEvent).State = EntityState.Detached;
         }
     }
 }
コード例 #5
0
        public async Task FlushPendingEvents_absorbs_exception_caused_by_that_some_pending_event_already_deleted_since_loaded()
        {
            // Arrange
            var         completionSource = new TaskCompletionSource <bool>();
            IMessageBus messageBus       = new AwaitingMessageBus(completionSource.Task);
            var         fixture          = new Fixture();
            FakeUser    user             = fixture.Create <FakeUser>();

            user.ChangeUsername(fixture.Create(nameof(user.Username)));
            var eventStore = new SqlEventStore(CreateDbContext, _serializer);
            await eventStore.SaveEvents <FakeUser>(user.FlushPendingEvents());

            var sut = new SqlEventPublisher(CreateDbContext, _serializer, messageBus);

            // Act
            Func <Task> action = async() =>
            {
                Task flushTask = sut.FlushPendingEvents(user.Id, CancellationToken.None);

                using (EventStoreDbContext db = CreateDbContext())
                {
                    List <PendingEvent> pendingEvents = await db
                                                        .PendingEvents
                                                        .Where(e => e.AggregateId == user.Id)
                                                        .OrderBy(e => e.Version)
                                                        .Take(1)
                                                        .ToListAsync();

                    db.PendingEvents.RemoveRange(pendingEvents);
                    await db.SaveChangesAsync();
                }

                completionSource.SetResult(true);
                await flushTask;
            };

            // Assert
            action.ShouldNotThrow();
            using (EventStoreDbContext db = CreateDbContext())
            {
                (await db.PendingEvents.AnyAsync(e => e.AggregateId == user.Id))
                .Should().BeFalse("all pending events should be deleted");
            }
        }
コード例 #6
0
        private static async Task RemoveEvents(
            EventStoreDbContext context,
            List <PendingEvent> pendingEvents,
            CancellationToken cancellationToken)
        {
            foreach (PendingEvent pendingEvent in pendingEvents)
            {
                try
                {
                    context.PendingEvents.Remove(pendingEvent);
                    await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
                }
#if NETSTANDARD2_0
                catch (DbUpdateConcurrencyException)
#else
                catch (DbUpdateConcurrencyException exception)
                    when(exception.InnerException is OptimisticConcurrencyException)
#endif
                {
                    context.Entry(pendingEvent).State = EntityState.Detached;
                }
            }
        }
コード例 #7
0
        private async Task SaveChanges <T>(
            EventStoreDbContext context,
            Guid sourceId,
            Guid?correlationId,
            CancellationToken cancellationToken)
            where T : class, IEventSourced
        {
#if NETSTANDARD2_0
            try
            {
                using (IDbContextTransaction transaction = await
                                                           context.Database.BeginTransactionAsync(cancellationToken).ConfigureAwait(false))
                {
                    await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);

                    transaction.Commit();
                }
            }
            catch (DbUpdateException exception) when(correlationId.HasValue)
            {
                IQueryable <Correlation> query = from c in context.Correlations
                                                 where c.AggregateId == sourceId && c.CorrelationId == correlationId
                                                 select c;

                if (await query.AnyAsync().ConfigureAwait(false))
                {
                    throw new DuplicateCorrelationException(
                              typeof(T),
                              sourceId,
                              correlationId.Value,
                              exception);
                }

                throw;
            }
#else
            try
            {
                await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
            }
            catch (DbUpdateException exception)
                when(exception.InnerException is UpdateException)
                {
                    var updateException = (UpdateException)exception.InnerException;

                    Correlation correlation = updateException
                                              .StateEntries
                                              .Select(s => s.Entity)
                                              .OfType <Correlation>()
                                              .FirstOrDefault();

                    if (correlation != null)
                    {
                        throw new DuplicateCorrelationException(
                                  typeof(T),
                                  sourceId,
                                  correlation.CorrelationId,
                                  exception);
                    }

                    throw;
                }
#endif
        }