Example #1
0
        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);
        }
Example #2
0
        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}");
                }
            }
        }