public async Task <AggregateRootCheckpointResult> AppendAsync( AggregateRootCheckpoint <TPayload> checkpoint, CancellationToken token = default) { PreConditions.NotNull(checkpoint, nameof(checkpoint)); PreConditions.NotNullOrEmpty(checkpoint.AggregateRootId, nameof(checkpoint.AggregateRootId)); PreConditions.NotNull(checkpoint.AggregateRootType, nameof(checkpoint.AggregateRootType)); PreConditions.Nonnegative(checkpoint.AggregateRootGeneration, nameof(checkpoint.AggregateRootGeneration)); PreConditions.Nonnegative(checkpoint.AggregateRootVersion, nameof(checkpoint.AggregateRootVersion)); var record = AggregateRootCheckpointRecordPortAdapter.ToRecord(checkpoint, _binarySerializer); var parameters = DbParameterProvider.ReflectionParameters(record); var tables = _options.Tables.DomainModelOptions; var insertCheckpointIndexSql = $"INSERT INTO `{tables.AggregateRootCheckpointIndices}`(`AggregateRootId`,`AggregateRootType`,`AggregateRootVersion`,`AggregateRootGeneration`,`CreatedTimestamp`) VALUES(@AggregateRootId,@AggregateRootType,@AggregateRootVersion,@AggregateRootGeneration,@CreatedTimestamp)"; var insertCheckpointSql = $"INSERT INTO `{tables.AggregateRootCheckpoints}`(`AggregateRootId`,`Payload`) VALUES (@AggregateRootId,@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($"{record.AggregateRootType}: [Ignored]find duplicated aggregate root checkpoint from mysql state backend:{inner.Message}."); return(false); } _logger.LogError($"Append aggregate root checkpoint has unknown exception: {LogFormatter.PrintException(exc)}."); return(true); } var affectedRows = await AsyncExecutorWithRetries.ExecuteWithRetriesAsync(async attempt => { return(await _db.ExecuteAsync( $"{insertCheckpointIndexSql};{insertCheckpointSql};", command => command.Parameters.AddRange(parameters), token)); }, maxNumErrorTries, ErrorFilter, maxExecutionTime).ConfigureAwait(false); if (affectedRows != expectedRows) { return(AggregateRootCheckpointResult.StorageFailed(record.AggregateRootId, $"The affected rows returned MySql state backend is incorrect when append aggregate root checkpoint, expected: {expectedRows}, actual: {affectedRows}.")); } return(AggregateRootCheckpointResult.StorageSucceed(record.AggregateRootId)); }
public static AggregateRootCheckpointRecord ToRecord <TPayload>( AggregateRootCheckpoint <TPayload> checkpoint, IBinarySerializer serializer) where TPayload : ISerializationMetadataProvider { return(new AggregateRootCheckpointRecord() { AggregateRootId = checkpoint.AggregateRootId, AggregateRootType = checkpoint.AggregateRootType.FullName, AggregateRootGeneration = checkpoint.AggregateRootGeneration, AggregateRootVersion = checkpoint.AggregateRootVersion, Payload = serializer.Serialize(checkpoint.Payload, checkpoint.Payload.IgnoreKeys) }); }