public void CheckSubscribeThenPublishFromAnotherThreadShouldReceiveEvent() { // Arrange var eventAggregator = new EventAggregator(); var source = new EventSource(eventAggregator); var receiver = new EventReceiver(eventAggregator); var data = EventData.Random(); // Act var unsubscriber = receiver.Subscribe(); Task.Run(() => { source.Emit(data); }); receiver.Wait(); // Assert Assert.True(receiver.EventReceived); Assert.Equal(data, receiver.Data); Assert.Equal(data.TestGuid, receiver.Data.TestGuid); Assert.Equal(data.TestInteger, receiver.Data.TestInteger); Assert.Equal(data.TestStr, receiver.Data.TestStr); // Cleanup unsubscriber.Dispose(); eventAggregator.Dispose(); receiver.Dispose(); }
public void CheckSubscribeThenUnsubscribeShouldNotReceivedEvent() { // Arrange var eventAggregator = new EventAggregator(); var source = new EventSource(eventAggregator); var receiver = new EventReceiver(eventAggregator); var data = EventData.Random(); // Act var unsubscriber = receiver.Subscribe(); unsubscriber.Dispose(); source.Emit(data); receiver.Wait(); // Assert Assert.False(receiver.EventReceived); Assert.Null(receiver.Data); // Cleanup eventAggregator.Dispose(); receiver.Dispose(); }
public void RunInitialize() { mongoDatabase = mongoClient.GetDatabase(Guid.NewGuid().ToString()); var log = new SemanticLog(new ILogChannel[0], new ILogAppender[0], () => new JsonLogWriter(Formatting.Indented, true)); eventConsumerInfos = new MongoEventConsumerInfoRepository(mongoDatabase); eventNotifier = new DefaultEventNotifier(new InMemoryPubSub()); eventStore = new MongoEventStore(mongoDatabase, eventNotifier); eventConsumer = new MyEventConsumer(NumEvents); eventReceiver = new EventReceiver(formatter, eventStore, eventNotifier, eventConsumerInfos, log); eventReceiver.Subscribe(eventConsumer); }
public void CheckSubscriberWithoutPublisherShouldNotReceivedEvent() { // Arrange var eventAggregator = new EventAggregator(); var receiver = new EventReceiver(eventAggregator); // Act var unsubscriber = receiver.Subscribe(); receiver.Wait(); // Assert Assert.False(receiver.EventReceived); Assert.Null(receiver.Data); // Cleanup unsubscriber.Dispose(); eventAggregator.Dispose(); receiver.Dispose(); }
public void CheckTwoSubscribersShouldReceiveSameEvent() { // Arrange var eventAggregator = new EventAggregator(); var source = new EventSource(eventAggregator); var firstReceiver = new EventReceiver(eventAggregator); var secondReceiver = new EventReceiver(eventAggregator); var data = EventData.Random(); // Act var firstUnsubscriber = firstReceiver.Subscribe(); var secondUnsubscriber = secondReceiver.Subscribe(); source.Emit(data); firstReceiver.Wait(); secondReceiver.Wait(); // Assert Assert.True(firstReceiver.EventReceived); Assert.Equal(data, firstReceiver.Data); Assert.Equal(data.TestGuid, firstReceiver.Data.TestGuid); Assert.Equal(data.TestInteger, firstReceiver.Data.TestInteger); Assert.Equal(data.TestStr, firstReceiver.Data.TestStr); Assert.True(secondReceiver.EventReceived); Assert.Equal(data, secondReceiver.Data); Assert.Equal(data.TestGuid, secondReceiver.Data.TestGuid); Assert.Equal(data.TestInteger, secondReceiver.Data.TestInteger); Assert.Equal(data.TestStr, secondReceiver.Data.TestStr); // Cleanup firstUnsubscriber.Dispose(); secondUnsubscriber.Dispose(); eventAggregator.Dispose(); firstReceiver.Dispose(); secondReceiver.Dispose(); }
private IDisposable BinaryReferenceEventsProducing(CancellationToken cancellationToken) { async Task ProcessAsync(KafkaEvent <ObjectVersionCreatingEvent> @event) { var objectId = @event.Source.ObjectId; var versionId = @event.Source.CurrentVersionId; IReadOnlyCollection <ObjectVersionRecord> versionRecords; if (string.IsNullOrEmpty(versionId)) { var policy = CreateGetObjectVersionsResiliencePolicy(); versionRecords = await policy.ExecuteAsync(() => _objectsStorageReader.GetObjectVersions(objectId, versionId)); if (versionRecords == null) { _logger.LogWarning( "{taskName}: Got an event for the object with id = '{objectId}' that was not eventually created. The event will be skipped.", nameof(ObjectVersionCreatedEventsProducing), objectId); return; } } else { versionRecords = await _objectsStorageReader.GetObjectVersions(objectId, versionId); } _logger.LogInformation( "{taskName}: There are '{versionsCount}' new versions were created after the versionId = {versionId} " + "for the object id = '{objectId}'.", nameof(BinaryReferenceEventsProducing), versionRecords.Count, versionId, objectId); foreach (var record in versionRecords) { var fileInfos = record.Elements .Where(x => x.Value is IBinaryElementValue binaryValue && !string.IsNullOrEmpty(binaryValue.Raw)) .Select(x => (TemplateCode: x.TemplateCode, FileKey: ((IBinaryElementValue)x.Value).Raw)) .ToList(); foreach (var fileInfo in fileInfos) { await _eventSender.SendAsync( _binariesUsingsTopic, new BinaryReferencedEvent(objectId, record.VersionId, fileInfo.TemplateCode, fileInfo.FileKey, record.LastModified)); _logger.LogInformation( "{taskName}: Event for binary reference {fileKey} for element with templateCode = '{templateCode}' " + "for object id = '{objectId}' and versionId = {versionId} sent to {topic}.", nameof(BinaryReferenceEventsProducing), fileInfo.FileKey, fileInfo.TemplateCode, record.Id, record.VersionId, _binariesUsingsTopic); } } await _binariesEventReceiver.CommitAsync(@event); } var observable = _binariesEventReceiver.Subscribe <ObjectVersionCreatingEvent>(cancellationToken); return(observable .Do(@event => { var retry = CreateRetryPolicy(_logger, nameof(BinaryReferenceEventsProducing)); retry.Execute(() => ProcessAsync(@event).GetAwaiter().GetResult()); }) .Subscribe()); }
private IDisposable ObjectVersionCreatedEventsProducing(CancellationToken cancellationToken) { async Task ProcessAsync(KafkaEvent <ObjectVersionCreatingEvent> @event) { var objectId = @event.Source.ObjectId; var versionId = @event.Source.CurrentVersionId; IReadOnlyCollection <ObjectVersionRecord> versionRecords; if (string.IsNullOrEmpty(versionId)) { var policy = CreateGetObjectVersionsResiliencePolicy(); versionRecords = await policy.ExecuteAsync(() => _objectsStorageReader.GetObjectVersions(objectId, versionId)); if (versionRecords == null) { _logger.LogWarning( "{taskName}: Got an event for the object with id = '{objectId}' that was not eventually created. The event will be skipped.", nameof(ObjectVersionCreatedEventsProducing), objectId); return; } } else { versionRecords = await _objectsStorageReader.GetObjectVersions(objectId, versionId); } _logger.LogInformation( "{taskName}: There are '{versionsCount}' new versions were created after the versionId = {versionId} for the object id = '{objectId}'.", nameof(ObjectVersionCreatedEventsProducing), versionRecords.Count, versionId, objectId); foreach (var record in versionRecords) { var versionCreatedEvent = new ObjectVersionCreatedEvent( record.Id, record.VersionId, record.VersionIndex, record.Author, record.Properties, record.LastModified); await _eventSender.SendAsync(_objectVersionsTopic, versionCreatedEvent); _logger.LogInformation( "{taskName}: Event for object id = '{objectId}' and versionId = {versionId} sent to {topic}.", nameof(ObjectVersionCreatedEventsProducing), record.Id, record.VersionId, _objectVersionsTopic); } await _versionEventReceiver.CommitAsync(@event); } var observable = _versionEventReceiver.Subscribe <ObjectVersionCreatingEvent>(cancellationToken); return(observable .Do(@event => { var retry = CreateRetryPolicy(_logger, nameof(ObjectVersionCreatedEventsProducing)); retry.Execute(() => ProcessAsync(@event).GetAwaiter().GetResult()); }) .Subscribe()); }
private IDisposable CleanupBinaries(int batchSize, TimeSpan delay, CancellationToken cancellationToken) { (IReadOnlyCollection <KafkaEvent <SessionCreatingEvent> >, DateTime) EvaluateExpiredSessions( IEnumerable <KafkaEvent <SessionCreatingEvent> > sessionCreatingEvents, IEnumerable <KafkaEvent <BinaryReferencedEvent> > referenceEvents) { var lastReferenceEvent = referenceEvents.Last(); var periodEnd = lastReferenceEvent.Source.ReferencedAt ?? lastReferenceEvent.Timestamp.UtcDateTime; _logger.LogInformation("Evaluating the number of expired sessions by '{periodEnd:u}'.", periodEnd); return(sessionCreatingEvents.Where(x => x.Source.ExpiresAt <= periodEnd).ToList(), periodEnd); } async Task ProcessAsync(IList <KafkaEvent <SessionCreatingEvent> > sessionCreatingEvents) { var oldestSessionDate = sessionCreatingEvents[0].Timestamp.UtcDateTime; var dateToStart = oldestSessionDate.Subtract(SafetyPeriod); _logger.LogInformation( "Starting to process '{totalSessionsCount}' sessions. Oldest session date: {oldestSessionDate:u}. " + "Binary reference events stream will be read starting from {dateToStart:u}.", sessionCreatingEvents.Count, oldestSessionDate, dateToStart); var referenceEventsPolicy = CreateReferenceEventsReadingPolicy(_logger, dateToStart, delay); var referenceEvents = await referenceEventsPolicy.ExecuteAsync( async() => { var result = await _referencesEventReader.ReadAsync <BinaryReferencedEvent>( _binariesReferencesTopicName, dateToStart); return(new List <KafkaEvent <BinaryReferencedEvent> >(result)); }); _logger.LogInformation( "'{referenceEventsCount}' events of type {eventType} read in time interval from {dateToStart:u} till now.", referenceEvents.Count, typeof(BinaryReferencedEvent).Name, dateToStart); var(expiredSessionEvents, periodEnd) = EvaluateExpiredSessions(sessionCreatingEvents, referenceEvents); while (expiredSessionEvents.Count != sessionCreatingEvents.Count) { _logger.LogWarning( "There are only '{expiredSessionsCount}' of '{totalSessionsCount}' sessions expired by {periodEnd:u} in current batch. " + "The {workerJobType} will now wait for {totalWaitTime:g}.", expiredSessionEvents.Count, sessionCreatingEvents.Count, periodEnd, typeof(BinariesCleanupJob).Name, delay); await Task.Delay(delay, cancellationToken); var additional = await _referencesEventReader.ReadAsync <BinaryReferencedEvent>(_binariesReferencesTopicName, periodEnd.Subtract(SafetyPeriod)); referenceEvents.AddRange(additional); var(extendedExpired, extendedPeriodEnd) = EvaluateExpiredSessions(sessionCreatingEvents, referenceEvents); expiredSessionEvents = extendedExpired; periodEnd = extendedPeriodEnd; } var sessionsWithReferences = new HashSet <Guid>(referenceEvents.Select(EvaluateSessionId)); _logger.LogInformation( "Starting to archive unreferenced sessions in batch of '{expiredSessionsCount}' sessions " + "considering that '{referencedSessionsCount}' sessions were referenced in time interval from {dateToStart:u} till now.", expiredSessionEvents.Count, sessionsWithReferences.Count, dateToStart); var archievedSessionsCount = await ArchieveUnreferencedBinaries(expiredSessionEvents, sessionsWithReferences, cancellationToken); _logger.LogInformation( "Total '{totalSessionsCount}' sessions has been processed, '{archievedSessionsCount}' were archived.", sessionCreatingEvents.Count, archievedSessionsCount); } var observable = _sessionsEventReceiver.Subscribe <SessionCreatingEvent>(cancellationToken); return(observable .Buffer(batchSize) .Do(batch => { var retry = CreateRetryPolicy(_logger); retry.Execute(() => ProcessAsync(batch).GetAwaiter().GetResult()); }) .Subscribe()); }
public void CheckLongRunningHandlerShouldNotBlockOtherHandler() { // Arrange var timerElapsed = new ManualResetEventSlim(false); var timer = new Timer( _ => { timerElapsed.Set(); }, null, 1000, 0); var eventAggregator = new EventAggregator(); var source = new EventSource(eventAggregator); var firstReceiver = new EventReceiver(eventAggregator, () => { timerElapsed.Wait(); }); var secondReceiver = new EventReceiver(eventAggregator); var data = EventData.Random(); // Act var firstUnsubscriber = firstReceiver.Subscribe(); var secondUnsubscriber = secondReceiver.Subscribe(); source.Emit(data); firstReceiver.Wait(); secondReceiver.Wait(); // Assert Assert.False(firstReceiver.EventReceived); Assert.True(secondReceiver.EventReceived); Assert.Null(firstReceiver.Data); Assert.Equal(data, secondReceiver.Data); Assert.Equal(data.TestGuid, secondReceiver.Data.TestGuid); Assert.Equal(data.TestInteger, secondReceiver.Data.TestInteger); Assert.Equal(data.TestStr, secondReceiver.Data.TestStr); firstReceiver.Wait(1000); Assert.True(firstReceiver.EventReceived); Assert.Equal(data, firstReceiver.Data); Assert.Equal(data.TestGuid, firstReceiver.Data.TestGuid); Assert.Equal(data.TestInteger, firstReceiver.Data.TestInteger); Assert.Equal(data.TestStr, firstReceiver.Data.TestStr); // Cleanup firstUnsubscriber.Dispose(); secondUnsubscriber.Dispose(); eventAggregator.Dispose(); firstReceiver.Dispose(); secondReceiver.Dispose(); timer.Dispose(); timerElapsed.Dispose(); }