private async Task SendIfAny( string category, IEventStoreContext context, NpgsqlConnection connection) { bool hasMoreStreams; do { var streamsInOutbox = await GetTopOfOutboxStreams(connection); hasMoreStreams = streamsInOutbox.Count == MaxStreamsPerRead; foreach (var id in streamsInOutbox) { var stream = new StreamId(category, id); var lockId = stream.GetLockId(); if (await TryLock(lockId, connection)) { var events = await GetEvents(stream, connection); if (events.Count == 0) { await Unlock(lockId, connection); continue; } var operation = new SendingOperation( stream, lockId, events, connection, context.GetPublisher(stream)); await operation.SendAsync(); } } } while (hasMoreStreams); }
public async Task <ISendingOperation> PrepareSendingAsync( StreamId stream, IReadOnlyCollection <RecordedEvent> events, NpgsqlConnection connection, NpgsqlTransaction transaction) { if (events.Count == 0) { throw new ArgumentException("Events is empty", nameof(events)); } var streamLock = stream.GetLockId(); long lastSentEventNumber; await using (var prepareSending = BuildPrepareCommand(stream, streamLock, connection, transaction)) { await prepareSending.PrepareAsync(); await using var reader = await prepareSending.ExecuteReaderAsync(); await reader.NextResultAsync(); await reader.ReadAsync(); lastSentEventNumber = reader.GetInt64(0); } var startSendFrom = lastSentEventNumber + 1; if (events.First().Number == startSendFrom) { return(new SendingOperation( stream, streamLock, events, connection, _context.GetPublisher(stream))); } var readResult = await _reader.ReadStreamEventsForwardAsync( stream, startSendFrom, int.MaxValue, connection, transaction); ValidateReadResult(readResult, startSendFrom, events.Count); events = readResult.Events; return(new SendingOperation(stream, streamLock, events, connection, _context.GetPublisher(stream))); void ValidateReadResult(EventSliceReadResult result, long firstEventNumber, int prevEventsCount) { if (result.Status != ReadStatus.Success) { throw new InvalidOperationException($"Events read status is {result.Status}"); } if (result.Events.First().Number != firstEventNumber) { throw new InvalidOperationException( $"First event must have number {firstEventNumber} but had {result.Events.First().Number}"); } if (result.Events.Count <= prevEventsCount) { throw new InvalidOperationException( $"Expected events count must be greater then {prevEventsCount}"); } } }