public async Task <StreamResponse> WriteAsync( StreamId streamId, IReadOnlyCollection <object> events, StreamVersion version, StreamWriteOptions?options, CancellationToken cancellationToken) { var metadata = await metadataReader .GetAsync(streamId, cancellationToken) .ConfigureAwait(false); validator.Validate(metadata, version); var batch = batchProducer .FromEvents(events, metadata, options); var response = await batchWriter .WriteAsync(batch, cancellationToken) .ConfigureAwait(false); return(new StreamResponse( response.StreamId, response.Version, response.Timestamp, response.State)); }
public void Validate(IStreamMetadata metadata, StreamVersion version) { if (metadata.State == StreamState.Closed) { throw new StreamClosedException(metadata.StreamId); } }
public void Should_Be_GreatherThan_Using_CompareTo( [Frozen] long version, StreamVersion sut) => sut .CompareTo(version + 1) .Should() .Be(-1);
public async Task RememberConsumedStreamVersionAsync_WhenSkipCurrentFlagIsTrue_CommitsOnlyProcessedEvents( [Frozen] StreamVersion version, [Frozen] CommitStreamVersionFMock commitStreamVersionMock, [Frozen] Mock <IEventStreamReader> readerMock, [Frozen] JournaledEvent[] events, EventStreamConsumer consumer) { var streamVersion = version.Increment(events.Length); readerMock .Setup(self => self.StreamVersion) .Returns(streamVersion); await consumer.ReceiveEventsAsync(); var handledEvents = 0; foreach (var e in consumer.EnumerateEvents()) { handledEvents++; await consumer.CommitProcessedStreamVersionAsync(skipCurrent : true); } Assert.Equal(handledEvents - 1, commitStreamVersionMock.CallsCount); Assert.Equal(streamVersion.Decrement(), commitStreamVersionMock.CommitedVersion); }
public async Task RememberConsumedStreamVersionAsync_WhenLatestManuallyCommitedVersionEqualsToStreamCurrent_SkipCommitOnReceiveAsync( [Frozen] StreamVersion version, [Frozen] CommitStreamVersionFMock commitStreamVersionMock, [Frozen] Mock <IEventStreamReader> readerMock, [Frozen] JournaledEvent[] events, EventStreamConsumer consumer) { var streamVersion = version.Increment(events.Length); readerMock .Setup(self => self.StreamVersion) .Returns(streamVersion); await consumer.ReceiveEventsAsync(); var handledEvents = 0; foreach (var e in consumer.EnumerateEvents()) { handledEvents++; await consumer.CommitProcessedStreamVersionAsync(); } await consumer.ReceiveEventsAsync(); Assert.Equal(handledEvents, commitStreamVersionMock.CallsCount); Assert.Equal(streamVersion, commitStreamVersionMock.CommitedVersion); }
public void Should_Be_EqualTo_Using_CompareTo( [Frozen] long version, StreamVersion sut) => sut .CompareTo(version) .Should() .Be(0);
public async Task CommitStreamReaderPositionAsync( string streamName, EventStreamReaderId readerId, StreamVersion readerVersion) { Require.NotEmpty(streamName, "streamName"); Require.NotNull(readerId, "readerId"); var properties = await m_table.ReadStreamReaderPropertiesAsync(streamName, readerId); if (properties == null) { await m_table.InserStreamReaderPropertiesAsync( streamName, readerId, readerVersion); } else { var readerVersionValue = (int)readerVersion; var savedVersionValue = (int)properties[EventJournalTableRowPropertyNames.Version]; var etag = (string)properties[KnownProperties.ETag]; Ensure.True(savedVersionValue <= readerVersionValue, "Saved reader stream version is greater then passed value."); if (readerVersionValue != savedVersionValue) { await m_table.UpdateStreamReaderPropertiesAsync(streamName, readerId, readerVersion, etag); } } }
public void Should_Be_LessThan_Using_CompareTo( [Frozen] long version, StreamVersion sut) => sut .CompareTo(version - 1) .Should() .Be(1);
public void Can_Get_Version_As_Long_FromStreamVersion( [Frozen] long version, StreamVersion sut) => StreamVersion .FromStreamVersion(sut) .Should() .Be(version);
public void Should_Be_Equal_When_InnerVersion_Has_The_Same_Value( [Frozen] long version, StreamVersion left, StreamVersion right) => (left == right) .Should() .BeTrue();
protected override async Task <EventProcessingResult> TryProcessEventFromConsumerAsync( IEventStreamConsumer consumer, StreamVersion notificationStreamVersion) { foreach (var journaledEvent in consumer.EnumerateEvents()) { var failed = false; try { await ProcessEventAsync(journaledEvent); } catch (Exception exception) { ListenerLogger.Error( exception, "Processing event {EventId} of type {EventType} from stream {Stream} failed.", journaledEvent.EventId, journaledEvent.EventTypeName, consumer.StreamName); failed = true; } if (failed) { await consumer.CommitProcessedStreamVersionAsync(skipCurrent : true); return(new EventProcessingResult(false, false)); } } return(new EventProcessingResult(true, true)); }
public async IAsyncEnumerable <IEvent> ReadAsync( StreamId streamId, StreamVersion fromVersion, StreamReadFilter?filter, [EnumeratorCancellation] CancellationToken cancellationToken) { var metadata = await metadataReader .GetAsync(streamId, cancellationToken) .ConfigureAwait(false); readValidator.Validate( metadata, filter?.RequiredVersion ?? StreamVersion.Any); // If we don't have any events in the stream, then skip reading from stream. if (metadata.Version == 0) { yield break; } await foreach (var evt in streamIterator .ReadAsync(streamId, fromVersion, filter, cancellationToken) .ConfigureAwait(false)) { yield return(evt); } }
public Task Invoke(StreamVersion version) { CallsCount++; CommitedVersion = version; return(TaskDone.Done); }
public Task Invoke(StreamVersion version) { CallsCount++; CommitedVersion = version; return TaskDone.Done; }
public async Task DeleteAsync(string streamName, StreamVersion streamVersion) { Require.NotEmpty(streamName, "streamName"); try { var operation = m_table.PrepareBatchOperation(); operation.Delete( partitionKey: GetPartitionKey(streamName), rowKey: GetRowKey(streamName, streamVersion), etag: "*"); await operation.ExecuteAsync(); } catch (BatchOperationException exception) { if (exception.HttpStatusCode != HttpStatusCode.NotFound) { throw; } s_logger.Debug(exception, "Stream {SteamName} version {Version} pending notification record has been deleted.", streamName, streamVersion); } }
public async Task <IDictionary <string, List <EventStreamUpdated> > > LoadAsync() { var result = new Dictionary <string, List <EventStreamUpdated> >(); var query = m_table.PrepareEntityGetAllQuery(); var queryResult = await query.ExecuteAsync(); foreach (var row in queryResult) { var rowKey = (string)row[KnownProperties.RowKey]; var rowKeyParts = rowKey.Split('|'); var streamName = rowKeyParts[0]; var fromVersion = StreamVersion.Parse(rowKeyParts[1]); var toVersion = StreamVersion.Create((int)row["ToVersion"]); List <EventStreamUpdated> streamNotifications; if (result.ContainsKey(streamName)) { streamNotifications = result[streamName]; } else { streamNotifications = new List <EventStreamUpdated>(); result[streamName] = streamNotifications; } streamNotifications.Add(new EventStreamUpdated(streamName, fromVersion, toVersion)); } return(result); }
public EventStreamHeader(string etag, StreamVersion version) { Require.NotNull(etag, "etag"); m_etag = etag; m_version = version; }
public void Should_Be_Constructed_With_Version( [Frozen] long version, StreamVersion sut) => sut .Value .Should() .Be(version);
public InitialCursorState(EventStreamHeader streamHeader, StreamVersion fromVersion, FetchEvents fetch) : base(streamHeader) { Require.NotNull(fetch, "fetch"); m_version = fromVersion; m_fetch = fetch; }
public async Task CreatedWriter_AppendsEventsAndMovesPositionForward(JournaledEvent[] dummyEvents) { var writer = await Connection.CreateStreamWriterAsync(StreamName); await writer.AppendEventsAsync(dummyEvents); Assert.Equal(StreamVersion.Create(dummyEvents.Length), writer.StreamVersion); }
private EventStreamCursor(EventStreamHeader streamHeader, StreamVersion fromVersion, FetchEvents fetch) { Require.NotNull(fetch, "fetch"); m_state = new InitialCursorState(streamHeader, fromVersion, fetch); m_slice = EventStreamSlice.Empty; m_cursorStreamVersion = fromVersion; }
public EventStreamUpdated(string streamName, StreamVersion fromVersion, StreamVersion toVersion) { Require.NotEmpty(streamName, "streamName"); StreamName = streamName; FromVersion = fromVersion; ToVersion = toVersion; }
public void TwoHeadersWithDifferentVersionValue_AreNotSame(string etag, StreamVersion version1, StreamVersion version2) { var header1 = new EventStreamHeader(etag, version1); var header2 = new EventStreamHeader(etag, version2); Assert.NotEqual(header1, header2); Assert.False(header1 == header2); }
public void Increment_IncreasesVersionByOne(int versionValue) { var expectedVersion = StreamVersion.Create(versionValue + 1); var version = StreamVersion.Create(versionValue); var incrementedVersion = version.Increment(); Assert.Equal(expectedVersion, incrementedVersion); }
public FetchingCursorState( EventStreamHeader streamHeader, StreamVersion sliceSteamVersion, FetchEvents fetch) : base(streamHeader) { Require.NotNull(fetch, "fetch"); m_sliceSteamVersion = sliceSteamVersion; m_fetch = fetch; }
public ConsumerDescription(StreamVersion streamVersion, string consumerName, EventStreamReaderId consumerId) { Require.NotNull(streamVersion, nameof(streamVersion)); Require.NotEmpty(consumerName, nameof(consumerName)); Require.NotNull(consumerId, nameof(consumerId)); StreamVersion = streamVersion; ConsumerName = consumerName; ConsumerId = consumerId; }
public StreamReaderDescription(string streamName, EventStreamReaderId streamReaderId, StreamVersion streamVersion) { Require.NotEmpty(streamName, nameof(streamName)); Require.NotNull(streamReaderId, nameof(streamReaderId)); Require.NotNull(streamVersion, nameof(streamVersion)); StreamName = streamName; StreamReaderId = streamReaderId; StreamVersion = streamVersion; }
public async Task AppendEventsAsync_WriteEventsToEndOfStream(string streamName) { // arrange var position = EventStreamHeader.Unknown; // act position = await AppendEventsAsync(streamName, batchNumber : 3); // assert Assert.Equal(StreamVersion.Create(30), position.Version); }
public async Task<IEventStreamReader> CreateStreamReaderAsync(string streamName, StreamVersion streamVersion) { Require.NotEmpty(streamName, "streamName"); var reader = new EventStreamReader( streamName, await m_journal.OpenEventStreamCursorAsync(streamName, streamVersion), version => m_journal.OpenEventStreamCursorAsync(streamName, version)); return reader; }
public async Task<IEventStreamCursor> OpenEventStreamCursorAsync(string streamName, StreamVersion fromVersion, int sliceSize) { Require.NotEmpty(streamName, "streamName"); Require.Positive(sliceSize, "sliceSize"); var position = await ReadEndOfStreamPositionAsync(streamName); return new EventStreamCursor( position, fromVersion, from => FetchEvents(streamName, from, position.Version, sliceSize)); }
public static Task <IEventStreamCursor> OpenEventStreamCursorAsync( this IEventJournal journal, string streamName, StreamVersion fromVersion) { Require.NotNull(journal, "journal"); return(journal.OpenEventStreamCursorAsync( streamName, fromVersion, Constants.Settings.EVENT_SLICE_SIZE)); }
public async Task <IEnumerable <StreamReaderDescription> > GetStreamReadersDescriptionsAsync(string streamName) { Require.NotEmpty(streamName, nameof(streamName)); var streamReadersProperties = await m_table.ReadAllStreamReadersPropertiesAsync(streamName); var descriptions = streamReadersProperties.Select(streamReaderProperties => new StreamReaderDescription( streamName, EventStreamReaderId.Parse(streamReaderProperties[KnownProperties.RowKey].ToString().Split('|').Last()), StreamVersion.Create((int)streamReaderProperties[EventJournalTableRowPropertyNames.Version]))); return(descriptions); }
public async Task Execute_ReturnsHeaderWithIncrementedVersion( [Frozen] StreamVersion currentVersion, JournaledEvent[] events, AppendOperation operation) { var targetVersion = currentVersion.Increment(events.Count()); operation.Prepare(events); var result = await operation.ExecuteAsync(); Assert.Equal(targetVersion, result.Version); }
public EventStreamCursor(EventStreamPosition position, StreamVersion fromVersion, FetchEvents fetch) { Require.NotNull(fetch, "fetch"); if (EventStreamPosition.IsNewStream(position)) { m_state = new EndOfStreamCursorState(); m_slice = EventStreamSlice.Empty; } else { m_state = new InitialCursorState(position, fromVersion, fetch); } }
public EventStreamConsumer( string consumerName, IEventStreamReader streamReader, IEventStreamConsumingSession session, StreamVersion commitedStreamVersion, Func<StreamVersion, Task> commitConsumedVersion) { Require.NotEmpty(consumerName, "consumerName"); Require.NotNull(streamReader, "streamReader"); Require.NotNull(session, "session"); Require.NotNull(commitConsumedVersion, "commitConsumedVersion"); m_consumerName = consumerName; m_reader = streamReader; m_session = session; m_commitConsumedVersion = commitConsumedVersion; m_commitedStreamVersion = commitedStreamVersion; }
public async Task<bool> ReceiveEventsAsync() { AssertConsumerWasNotClosed(); AssertConsumerIsNotInConsumingState(); if (!(await m_session.PromoteToLeaderAsync())) { return false; } if (m_receiving && m_commitedStreamVersion != m_reader.CurrentStreamVersion) { await m_commitConsumedVersion(m_reader.CurrentStreamVersion); m_commitedStreamVersion = m_reader.CurrentStreamVersion; m_eventSliceOffset = 0; } if (m_reader.IsCompleted) { await m_reader.ContinueAsync(); m_receiving = false; } if (m_reader.HasEvents) { await m_reader.ReadEventsAsync(); m_hasUnprocessedEvents = true; m_receiving = true; return true; } await m_session.FreeAsync(); m_receiving = false; return false; }
public async Task CommitStreamReaderPositionAsync( string streamName, string readerName, StreamVersion readerVersion) { Require.NotEmpty(streamName, "streamName"); Require.NotEmpty(readerName, "readerName"); var referenceRow = await ReadReferenceRowHeadAsync( streamName, "RDR_" + readerName); var operation = m_table.PrepareBatchOperation(); if (referenceRow == null) { operation.Insert( streamName, "RDR_" + readerName, new Dictionary<string, object> { { EventJournalTableRowPropertyNames.Version, (int)readerVersion } }); } else { operation.Merge( streamName, "RDR_" + readerName, (string)referenceRow[KnownProperties.ETag], new Dictionary<string, object> { { EventJournalTableRowPropertyNames.Version, (int)readerVersion } }); } await operation.ExecuteAsync(); }
private async Task<SortedList<StreamVersion, JournaledEvent>> FetchEvents( string stream, StreamVersion fromVersion, StreamVersion toVersion, int sliceSize) { var nextSliceVersion = fromVersion.Increment(sliceSize); if (nextSliceVersion >= toVersion) { nextSliceVersion = toVersion; } var query = m_table.PrepareEntityFilterRangeQuery( "(PartitionKey eq '{0}') and (RowKey ge '{1}' and RowKey le '{2}')".FormatString( stream, fromVersion.ToString(), nextSliceVersion.ToString()), JournaledEventPropertyNames.All); var queryResult = await query.ExecuteAsync(); var result = new SortedList<StreamVersion, JournaledEvent>(sliceSize); foreach (var properties in queryResult) { result.Add(StreamVersion.Parse((string)properties[KnownProperties.RowKey]), JournaledEvent.Create(properties)); } return result; }
private async Task<List<JournaledEvent>> ReadEventsPartialAsync(StreamVersion fromVersion, StreamVersion toVersion, int sliceSize = 1000) { var stream = await Journal.OpenEventStreamCursorAsync(StreamName, fromVersion, toVersion, sliceSize); var result = new List<JournaledEvent>(); while (!stream.EndOfStream) { await stream.FetchSlice(); result.AddRange(stream.Slice); } return result; }
private static void WriteEvents(string stream, StreamVersion version, IEnumerable<JournaledEvent> events, IBatchOperation batch) { var currentVersion = version; foreach (var journaledEvent in events) { currentVersion = currentVersion.Increment(1); // InsertOrReplace is faster then Insert operation, because storage engine // can skip etag checking. batch.InsertOrReplace(stream, currentVersion.ToString(), journaledEvent.ToDictionary()); } }
public async Task<IEventStreamCursor> OpenEventStreamCursorAsync( string streamName, StreamVersion fromVersion, StreamVersion toVersion, int sliceSize) { Require.NotEmpty(streamName, "streamName"); Require.Positive(sliceSize, "sliceSize"); var headProperties = await ReadHeadAsync(streamName); if (headProperties == null) { return EventStreamCursor.Empty; } return new EventStreamCursor( new EventStreamPosition(string.Empty, toVersion), fromVersion, from => FetchEvents(streamName, from, toVersion, sliceSize)); }
public async Task CommitProcessedStreamVersionAsync(bool skipCurrent) { AssertConsumerWasNotClosed(); if (m_consuming) { var eventOffset = skipCurrent ? m_eventSliceOffset : m_eventSliceOffset + 1; if (eventOffset <= m_commitedEventCount) { // current event has been commited. return; } var version = m_commitedStreamVersion.Increment(eventOffset - m_commitedEventCount); if (m_commitedStreamVersion < version) { await m_commitConsumedVersion(version); m_commitedStreamVersion = version; m_commitedEventCount++; } } else { await m_commitConsumedVersion(m_reader.CurrentStreamVersion); m_commitedStreamVersion = m_reader.CurrentStreamVersion; m_eventSliceOffset = 0; } }