protected override Task OnProcessingErrorAsync( Exception exception, EventProcessorPartition partition, string operationDescription, CancellationToken cancellationToken) { try { if (partition != null) { Console.Error.WriteLine( $"Exception on partition { partition.PartitionId } while " + $"performing { operationDescription }: {exception}"); } else { Console.Error.WriteLine( $"Exception while performing { operationDescription }: { exception }"); } } catch (Exception ex) { // It is very important that you always guard against exceptions // in your handler code; the processor does not have enough // understanding of your code to determine the correct action to // take. Any exceptions from your handlers go uncaught by the // processor and will NOT be handled in any way. Console.WriteLine($"Exception while processing events: { ex }"); } return(Task.CompletedTask); }
public Dictionary <string, string> GetTriggerDetails(EventProcessorPartition context) { if (Events.Length == 0) { return(new Dictionary <string, string>()); } string offset, enqueueTimeUtc, sequenceNumber; if (IsSingleDispatch) { offset = Events[0].Offset.ToString(CultureInfo.InvariantCulture); enqueueTimeUtc = Events[0].EnqueuedTime.ToString("o", CultureInfo.InvariantCulture); sequenceNumber = Events[0].SequenceNumber.ToString(CultureInfo.InvariantCulture); } else { EventData first = Events[0]; EventData last = Events[Events.Length - 1]; offset = $"{first.Offset}-{last.Offset}"; enqueueTimeUtc = $"{first.EnqueuedTime.ToString("o", CultureInfo.InvariantCulture)}-{last.EnqueuedTime.ToString("o", CultureInfo.InvariantCulture)}"; sequenceNumber = $"{first.SequenceNumber}-{last.SequenceNumber}"; } return(new Dictionary <string, string>() { { "PartionId", context.PartitionId }, { "Offset", offset }, { "EnqueueTimeUtc", enqueueTimeUtc }, { "SequenceNumber", sequenceNumber }, { "Count", Events.Length.ToString(CultureInfo.InvariantCulture) } }); }
public async Task EventProcesorCreatesScopeForEventProcessing() { using var cancellationSource = new CancellationTokenSource(); cancellationSource.CancelAfter(TimeSpan.FromSeconds(30)); using var listener = new ClientDiagnosticListener(EventDataInstrumentation.DiagnosticNamespace); var enqueuedTime = DateTimeOffset.UtcNow; var diagnosticId = 12; var partition = new EventProcessorPartition { PartitionId = "123" }; var fullyQualifiedNamespace = "namespace"; var eventHubName = "eventHub"; var mockProcessor = new Mock <EventProcessor <EventProcessorPartition> >(67, "consumerGroup", fullyQualifiedNamespace, eventHubName, Mock.Of <TokenCredential>(), default(EventProcessorOptions)) { CallBase = true }; var eventBatch = new List <EventData> { new EventData(new BinaryData(Array.Empty <byte>()), enqueuedTime: enqueuedTime), new EventData(new BinaryData(Array.Empty <byte>()), enqueuedTime: enqueuedTime) }; eventBatch.ForEach(evt => evt.Properties.Add(DiagnosticProperty.DiagnosticIdAttribute, (++diagnosticId).ToString())); await mockProcessor.Object.ProcessEventBatchAsync(partition, eventBatch, false, cancellationSource.Token); // Validate the diagnostics. diagnosticId -= eventBatch.Count; var expectedTags = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>(DiagnosticProperty.KindAttribute, DiagnosticProperty.ConsumerKind), new KeyValuePair <string, string>(DiagnosticProperty.EventHubAttribute, eventHubName), new KeyValuePair <string, string>(DiagnosticProperty.EndpointAttribute, fullyQualifiedNamespace) }; var scopes = listener.Scopes.ToList(); Assert.That(cancellationSource.IsCancellationRequested, Is.False, "The cancellation token should not have been signaled."); Assert.That(scopes.Select(scope => scope.Name), Has.All.EqualTo(DiagnosticProperty.EventProcessorProcessingActivityName), "The processing scopes should have the correct name."); for (var index = 0; index < eventBatch.Count; ++index) { var targetId = (++diagnosticId).ToString(); Assert.That(scopes.SelectMany(scope => scope.Links), Has.One.EqualTo(targetId), $"There should have been a link for the diagnostic identifier: { targetId }"); } foreach (var scope in scopes) { Assert.That(expectedTags, Is.SubsetOf(scope.Activity.Tags.ToList())); } }
public async Task EventProcesorAddsAttributesToLinkedActivitiesForEventProcessing() { using var cancellationSource = new CancellationTokenSource(); cancellationSource.CancelAfter(TimeSpan.FromSeconds(30)); using var listener = new ClientDiagnosticListener(EventDataInstrumentation.DiagnosticNamespace); var enqueuedTime = DateTimeOffset.UtcNow; var diagnosticId = "OMGHAI2U!"; var eventBatch = new List <EventData> { new EventData(new BinaryData(Array.Empty <byte>()), enqueuedTime: enqueuedTime) }; var partition = new EventProcessorPartition { PartitionId = "123" }; var fullyQualifiedNamespace = "namespace"; var eventHubName = "eventHub"; var mockProcessor = new Mock <EventProcessor <EventProcessorPartition> >(67, "consumerGroup", fullyQualifiedNamespace, eventHubName, Mock.Of <TokenCredential>(), default(EventProcessorOptions)) { CallBase = true }; eventBatch.ForEach(evt => evt.Properties.Add(DiagnosticProperty.DiagnosticIdAttribute, diagnosticId)); await mockProcessor.Object.ProcessEventBatchAsync(partition, eventBatch, false, cancellationSource.Token); // Validate the diagnostics. Assert.That(cancellationSource.IsCancellationRequested, Is.False, "The cancellation token should not have been signaled."); var processingScope = listener.Scopes.SingleOrDefault(scope => scope.Name == DiagnosticProperty.EventProcessorProcessingActivityName); Assert.That(processingScope, Is.Not.Null, "There should have been a single scope present for the processing activity."); var linkedActivity = processingScope.LinkedActivities.SingleOrDefault(a => a.ParentId == diagnosticId); Assert.That(linkedActivity, Is.Not.Null, "There should have been a single activity linked to the diagnostic identifier."); var expectedTags = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>(DiagnosticProperty.EnqueuedTimeAttribute, enqueuedTime.ToUnixTimeMilliseconds().ToString()) }; var tags = linkedActivity.Tags.ToList(); Assert.That(tags, Is.EquivalentTo(expectedTags), "The activity should have been tagged appropriately."); }
protected async override Task OnProcessingEventBatchAsync( IEnumerable <EventData> events, EventProcessorPartition partition, CancellationToken cancellationToken) { EventData lastEvent = null; try { Console.WriteLine($"Received events for partition { partition.PartitionId }"); foreach (var currentEvent in events) { Console.WriteLine($"Event: { currentEvent.EventBody }"); lastEvent = currentEvent; } if (lastEvent != null) { await CheckpointAsync( partition, lastEvent, cancellationToken) .ConfigureAwait(false); } } catch (Exception ex) { // It is very important that you always guard against exceptions in // your handler code; the processor does not have enough // understanding of your code to determine the correct action to take. // Any exceptions from your handlers go uncaught by the processor and // will NOT be redirected to the error handler. Console.WriteLine($"Exception while processing events: { ex }"); } }