Beispiel #1
0
        public async Task <DomainEventResult> AppendAsync(
            IDomainEvent @event,
            CancellationToken token = default)
        {
            if ([email protected]())
            {
                return(DomainEventResult.StorageFailed(@event.Id, $"The domain event: [{@event.Print()}] cannot be stored mysql state backend."));
            }

            var domainEventRecord = DomainEventRecordPortAdapter.ToDomainEventRecord(@event, _binarySerializer);
            var parameters        = DbParameterProvider.ReflectionParameters(domainEventRecord);

            var tables = _options.Tables.DomainEventOptions;
            var insertDomainEventIndexSql = $"INSERT INTO `{tables.DomainEventIndices}`(`DomainCommandId`,`DomainCommandType`,`DomainCommandVersion`,`AggregateRootId`,`AggregateRootType`,`AggregateRootVersion`,`AggregateRootGeneration`,`DomainEventId`,`DomainEventType`,`DomainEventVersion`,`DomainEventPayloadBytes`,`CreatedTimestamp`) VALUES(@DomainCommandId,@DomainCommandType,@DomainCommandVersion,@AggregateRootId,@AggregateRootType,@AggregateRootVersion,@AggregateRootGeneration,@DomainEventId,@DomainEventType,@DomainEventVersion,@DomainEventPayloadBytes,@CreatedTimestamp)";
            var insertDomainEventSql      = $"INSERT INTO `{tables.DomainEvents}`(`DomainEventId`,`Payload`) VALUES (@DomainEventId,@Payload)";

            var maxNumErrorTries = 3;
            var maxExecutionTime = TimeSpan.FromSeconds(3);
            var expectedRows     = 2;

            bool ErrorFilter(Exception exc, int attempt)
            {
                if (exc is MySqlException inner &&
                    inner.HasDuplicateEntry())
                {
                    _logger.LogWarning($"{domainEventRecord.AggregateRootType}: [Ignored]find duplicated domain event from mysql state backend:{inner.Message}.");

                    return(false);
                }

                _logger.LogError($"Append domain event has unknown exception: {LogFormatter.PrintException(exc)}.");

                return(true);
            }

            var affectedRows = await AsyncExecutorWithRetries.ExecuteWithRetriesAsync(async attempt =>
            {
                return(await _db.ExecuteAsync(
                           $"{insertDomainEventIndexSql};{insertDomainEventSql};",
                           command => command.Parameters.AddRange(parameters),
                           token));
            }, maxNumErrorTries, ErrorFilter, maxExecutionTime).ConfigureAwait(false);

            if (affectedRows != expectedRows)
            {
                return(DomainEventResult.StorageFailed(@event.Id,
                                                       $"The affected rows returned MySql state backend is incorrect, expected: {expectedRows}, actual: {affectedRows}."));
            }

            return(DomainEventResult.StorageSucceed(@event.Id));
        }
Beispiel #2
0
        public async Task <IEnumerable <IDomainEvent> > GetEventStreamAsync(
            string aggregateRootId,
            long startOffset        = 0,
            long endOffset          = long.MaxValue,
            CancellationToken token = default)
        {
            PreConditions.NotNullOrEmpty(aggregateRootId, nameof(aggregateRootId));
            PreConditions.Nonnegative(startOffset, nameof(startOffset));

            var tables = _options.Tables.DomainEventOptions;

            var sql = $"SELECT d.`DomainCommandId`,d.`DomainCommandType`,d.`DomainCommandVersion`,d.`AggregateRootId`,d.`AggregateRootType`,d.`AggregateRootVersion`,d.`AggregateRootGeneration`,d.`DomainEventId`,d.`DomainEventType`,d.`DomainEventVersion`,d.`CreatedTimestamp`, p.`Payload` FROM `{tables.DomainEventIndices}` d INNER JOIN `{tables.DomainEvents}` p ON d.`DomainEventId`=p.`DomainEventId` WHERE d.`AggregateRootId`=@AggregateRootId AND d.AggregateRootVersion>=@StartOffset AND d.AggregateRootVersion<@EndOffset";

            var records = await _db.ReadAsync <DomainEventRecord>(sql, new
            {
                AggregateRootId = aggregateRootId,
                StartOffset     = startOffset,
                EndOffset       = endOffset
            }, token);

            if (records.IsEmpty())
            {
                return(null);
            }

            var domainEvents = new List <IDomainEvent>();

            foreach (var record in records)
            {
                var domainEvent = DomainEventRecordPortAdapter.ToDomainEvent(record, _typeResolver, _binarySerializer);
                if (!domainEvent.IsValid())
                {
                    _logger.LogCritical($"Found illegal domain event from mysql state backend: {domainEvent.Print()}.");

                    continue;
                }

                domainEvents.Add(domainEvent);
            }

            return(domainEvents);
        }