async Task InvokeAfterReceiveTimeoutTrue() { const int ReceiveTimeoutInSeconds = 15; Log("Testing EventProcessorHost with InvokeProcessorAfterReceiveTimeout=true"); var emptyBatchReceiveEvents = new ConcurrentDictionary <string, AsyncAutoResetEvent>(); foreach (var partitionId in PartitionIds) { emptyBatchReceiveEvents[partitionId] = new AsyncAutoResetEvent(false); } var eventProcessorHost = new EventProcessorHost( string.Empty, PartitionReceiver.DefaultConsumerGroupName, this.EventHubConnectionString, this.StorageConnectionString, this.LeaseContainerName); var processorOptions = new EventProcessorOptions { ReceiveTimeout = TimeSpan.FromSeconds(ReceiveTimeoutInSeconds), InvokeProcessorAfterReceiveTimeout = true, MaxBatchSize = 100 }; var processorFactory = new TestEventProcessorFactory(); processorFactory.OnCreateProcessor += (f, createArgs) => { var processor = createArgs.Item2; string partitionId = createArgs.Item1.PartitionId; processor.OnOpen += (_, partitionContext) => Log($"Partition {partitionId} TestEventProcessor opened"); processor.OnProcessEvents += (_, eventsArgs) => { int eventCount = eventsArgs.Item2.events != null?eventsArgs.Item2.events.Count() : 0; Log($"Partition {partitionId} TestEventProcessor processing {eventCount} event(s)"); if (eventCount == 0) { var emptyBatchReceiveEvent = emptyBatchReceiveEvents[partitionId]; emptyBatchReceiveEvent.Set(); } }; }; await eventProcessorHost.RegisterEventProcessorFactoryAsync(processorFactory, processorOptions); try { Log("Waiting for each partition to receive an empty batch of events..."); foreach (var partitionId in PartitionIds) { var emptyBatchReceiveEvent = emptyBatchReceiveEvents[partitionId]; bool emptyBatchReceived = await emptyBatchReceiveEvent.WaitAsync(TimeSpan.FromSeconds(ReceiveTimeoutInSeconds * 2)); Assert.True(emptyBatchReceived, $"Partition {partitionId} didn't receive an empty batch!"); } } finally { Log("Calling UnregisterEventProcessorAsync"); await eventProcessorHost.UnregisterEventProcessorAsync(); } }
async Task MultipleConsumerGroups() { var customConsumerGroupName = "cgroup1"; // Generate a new lease container name that will be used through out the test. string leaseContainerName = Guid.NewGuid().ToString(); var consumerGroupNames = new[] { PartitionReceiver.DefaultConsumerGroupName, customConsumerGroupName }; var processorOptions = new EventProcessorOptions { ReceiveTimeout = TimeSpan.FromSeconds(15), MaxBatchSize = 100 }; var processorFactory = new TestEventProcessorFactory(); var partitionReceiveEvents = new ConcurrentDictionary <string, AsyncAutoResetEvent>(); var hosts = new List <EventProcessorHost>(); // Confirm that custom consumer group exists before starting hosts. try { // Create a receiver on the consumer group and try to receive. // Receive call will fail if consumer group is missing. var ehClient = EventHubClient.CreateFromConnectionString(this.EventHubConnectionString); var receiver = ehClient.CreateReceiver(customConsumerGroupName, this.PartitionIds.First(), PartitionReceiver.StartOfStream); await receiver.ReceiveAsync(1, TimeSpan.FromSeconds(5)); } catch (MessagingEntityNotFoundException) { throw new Exception($"Cunsumer group {customConsumerGroupName} cannot be found. MultipleConsumerGroups unit test requires consumer group '{customConsumerGroupName}' to be created before running the test."); } processorFactory.OnCreateProcessor += (f, createArgs) => { var processor = createArgs.Item2; string partitionId = createArgs.Item1.PartitionId; string hostName = createArgs.Item1.Owner; string consumerGroupName = createArgs.Item1.ConsumerGroupName; processor.OnOpen += (_, partitionContext) => Log($"{hostName} > {consumerGroupName} > Partition {partitionId} TestEventProcessor opened"); processor.OnClose += (_, closeArgs) => Log($"{hostName} > {consumerGroupName} > Partition {partitionId} TestEventProcessor closing: {closeArgs.Item2}"); processor.OnProcessError += (_, errorArgs) => Log($"{hostName} > {consumerGroupName} > Partition {partitionId} TestEventProcessor process error {errorArgs.Item2.Message}"); processor.OnProcessEvents += (_, eventsArgs) => { int eventCount = eventsArgs.Item2 != null?eventsArgs.Item2.events.Count() : 0; Log($"{hostName} > {consumerGroupName} > Partition {partitionId} TestEventProcessor processing {eventCount} event(s)"); if (eventCount > 0) { var receivedEvent = partitionReceiveEvents[consumerGroupName + "-" + partitionId]; receivedEvent.Set(); } }; }; try { // Register a new host for each consumer group. foreach (var consumerGroupName in consumerGroupNames) { var eventProcessorHost = new EventProcessorHost( string.Empty, consumerGroupName, this.EventHubConnectionString, this.StorageConnectionString, leaseContainerName); Log($"Calling RegisterEventProcessorAsync on consumer group {consumerGroupName}"); foreach (var partitionId in PartitionIds) { partitionReceiveEvents[consumerGroupName + "-" + partitionId] = new AsyncAutoResetEvent(false); } await eventProcessorHost.RegisterEventProcessorFactoryAsync(processorFactory, processorOptions); hosts.Add(eventProcessorHost); } Log("Sending an event to each partition"); var sendTasks = new List <Task>(); foreach (var partitionId in PartitionIds) { sendTasks.Add(this.SendToPartitionAsync(partitionId, $"{partitionId} event.", this.ConnectionStringBuilder.ToString())); } await Task.WhenAll(sendTasks); Log("Verifying an event was received by each partition for each consumer group"); foreach (var consumerGroupName in consumerGroupNames) { foreach (var partitionId in PartitionIds) { var receivedEvent = partitionReceiveEvents[consumerGroupName + "-" + partitionId]; bool partitionReceivedMessage = await receivedEvent.WaitAsync(TimeSpan.FromSeconds(30)); Assert.True(partitionReceivedMessage, $"ConsumerGroup {consumerGroupName} > Partition {partitionId} didn't receive any message!"); } } Log("Success"); } finally { Log("Calling UnregisterEventProcessorAsync on both hosts."); foreach (var eph in hosts) { await eph.UnregisterEventProcessorAsync(); } } }
async Task MultipleProcessorHosts() { Log("Testing with 2 EventProcessorHost instances"); var partitionReceiveEvents = new ConcurrentDictionary <string, AsyncAutoResetEvent>(); foreach (var partitionId in PartitionIds) { partitionReceiveEvents[partitionId] = new AsyncAutoResetEvent(false); } int hostCount = 2; var hosts = new List <EventProcessorHost>(); try { for (int i = 0; i < hostCount; i++) { Log("Creating EventProcessorHost"); var eventProcessorHost = new EventProcessorHost( string.Empty, // Passing empty as entity path here rsince path is already in EH connection string. PartitionReceiver.DefaultConsumerGroupName, this.EventHubConnectionString, this.StorageConnectionString, this.LeaseContainerName); hosts.Add(eventProcessorHost); Log($"Calling RegisterEventProcessorAsync"); var processorOptions = new EventProcessorOptions { ReceiveTimeout = TimeSpan.FromSeconds(10), InvokeProcessorAfterReceiveTimeout = true, MaxBatchSize = 100 }; var processorFactory = new TestEventProcessorFactory(); processorFactory.OnCreateProcessor += (f, createArgs) => { var processor = createArgs.Item2; string partitionId = createArgs.Item1.PartitionId; string hostName = createArgs.Item1.Owner; processor.OnOpen += (_, partitionContext) => Log($"{hostName} > Partition {partitionId} TestEventProcessor opened"); processor.OnClose += (_, closeArgs) => Log($"{hostName} > Partition {partitionId} TestEventProcessor closing: {closeArgs.Item2}"); processor.OnProcessError += (_, errorArgs) => Log($"{hostName} > Partition {partitionId} TestEventProcessor process error {errorArgs.Item2.Message}"); processor.OnProcessEvents += (_, eventsArgs) => { int eventCount = eventsArgs.Item2 != null?eventsArgs.Item2.events.Count() : 0; Log($"{hostName} > Partition {partitionId} TestEventProcessor processing {eventCount} event(s)"); if (eventCount > 0) { var receivedEvent = partitionReceiveEvents[partitionId]; receivedEvent.Set(); } }; }; await eventProcessorHost.RegisterEventProcessorFactoryAsync(processorFactory, processorOptions); } Log("Waiting for partition ownership to settle..."); await Task.Delay(TimeSpan.FromSeconds(30)); Log("Sending an event to each partition"); var sendTasks = new List <Task>(); foreach (var partitionId in PartitionIds) { sendTasks.Add(this.SendToPartitionAsync(partitionId, $"{partitionId} event.", this.ConnectionStringBuilder.ToString())); } await Task.WhenAll(sendTasks); Log("Verifying an event was received by each partition"); foreach (var partitionId in PartitionIds) { var receivedEvent = partitionReceiveEvents[partitionId]; bool partitionReceivedMessage = await receivedEvent.WaitAsync(TimeSpan.FromSeconds(30)); Assert.True(partitionReceivedMessage, $"Partition {partitionId} didn't receive any message!"); } } finally { var shutdownTasks = new List <Task>(); foreach (var host in hosts) { Log($"Host {host} Calling UnregisterEventProcessorAsync."); shutdownTasks.Add(host.UnregisterEventProcessorAsync()); } await Task.WhenAll(shutdownTasks); } }