public async Task ClaimOwnershipAsyncReturnsOnlyTheSuccessfullyClaimedOwnership()
        {
            var partitionManager = new InMemoryPartitionManager();
            var ownershipList    = new List <PartitionOwnership>();
            var ownershipCount   = 5;

            for (int i = 0; i < ownershipCount; i++)
            {
                ownershipList.Add(
                    new PartitionOwnership
                    (
                        "namespace",
                        "eventHubName",
                        "consumerGroup",
                        "ownerIdentifier",
                        $"partitionId { i }"
                    ));
            }

            await partitionManager.ClaimOwnershipAsync(ownershipList);

            // The ETags must have been set by the partition manager.

            var eTags = ownershipList.Select(ownership => ownership.ETag).ToList();

            ownershipList.Clear();

            // Use a valid eTag when 'i' is odd.  This way, we can expect 'ownershipCount / 2' successful
            // claims (rounded down).

            var expectedClaimedCount = ownershipCount / 2;

            for (int i = 0; i < ownershipCount; i++)
            {
                ownershipList.Add(
                    new PartitionOwnership
                    (
                        "namespace",
                        "eventHubName",
                        "consumerGroup",
                        "ownerIdentifier",
                        $"partitionId { i }",
                        offset: i,
                        eTag: i % 2 == 1 ? eTags[i] : null
                    ));
            }

            IEnumerable <PartitionOwnership> claimedOwnership = await partitionManager.ClaimOwnershipAsync(ownershipList);

            Assert.That(claimedOwnership, Is.Not.Null);
            Assert.That(claimedOwnership.Count, Is.EqualTo(expectedClaimedCount));
            Assert.That(claimedOwnership.OrderBy(ownership => ownership.Offset).SequenceEqual(ownershipList.Where(ownership => ownership.Offset % 2 == 1)), Is.True);
        }
        public async Task OwnershipClaimDoesNotInterfereWithOtherNamespaces()
        {
            var partitionManager = new InMemoryPartitionManager();
            var ownershipList    = new List <PartitionOwnership>();
            var firstOwnership   =
                new PartitionOwnership
                (
                    "namespace1",
                    "eventHubName",
                    "consumerGroup",
                    "ownerIdentifier",
                    "partitionId"
                );

            ownershipList.Add(firstOwnership);

            await partitionManager.ClaimOwnershipAsync(ownershipList);

            // ETag must have been set by the partition manager.

            var eTag = firstOwnership.ETag;

            ownershipList.Clear();

            var secondOwnership =
                new PartitionOwnership
                (
                    "namespace2",
                    "eventHubName",
                    "consumerGroup",
                    "ownerIdentifier",
                    "partitionId",
                    eTag: eTag
                );

            ownershipList.Add(secondOwnership);

            await partitionManager.ClaimOwnershipAsync(ownershipList);

            IEnumerable <PartitionOwnership> storedOwnership1 = await partitionManager.ListOwnershipAsync("namespace1", "eventHubName", "consumerGroup");

            IEnumerable <PartitionOwnership> storedOwnership2 = await partitionManager.ListOwnershipAsync("namespace2", "eventHubName", "consumerGroup");

            Assert.That(storedOwnership1, Is.Not.Null);
            Assert.That(storedOwnership1.Count, Is.EqualTo(1));
            Assert.That(storedOwnership1.Single(), Is.EqualTo(firstOwnership));

            Assert.That(storedOwnership2, Is.Not.Null);
            Assert.That(storedOwnership2.Count, Is.EqualTo(1));
            Assert.That(storedOwnership2.Single(), Is.EqualTo(secondOwnership));
        }
        public async Task ClaimOwnershipAsyncCanClaimMultipleOwnership()
        {
            var partitionManager = new InMemoryPartitionManager();
            var ownershipList    = new List <PartitionOwnership>();
            var ownershipCount   = 5;

            for (int i = 0; i < ownershipCount; i++)
            {
                ownershipList.Add(
                    new PartitionOwnership
                    (
                        "eventHubName",
                        "consumerGroup",
                        "ownerIdentifier",
                        $"partitionId { i }"
                    ));
            }

            await partitionManager.ClaimOwnershipAsync(ownershipList);

            var storedOwnership = await partitionManager.ListOwnershipAsync("eventHubName", "consumerGroup");

            Assert.That(storedOwnership, Is.Not.Null);
            Assert.That(storedOwnership.Count, Is.EqualTo(ownershipCount));
            Assert.That(storedOwnership.OrderBy(ownership => ownership.PartitionId).SequenceEqual(ownershipList), Is.True);
        }
        public async Task CheckpointUpdateUpdatesOwnershipInformation()
        {
            var partitionManager  = new InMemoryPartitionManager();
            var originalOwnership = new PartitionOwnership
                                        ("eventHubName", "consumerGroup", "ownerIdentifier", "partitionId", offset: 1, sequenceNumber: 2, lastModifiedTime: DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMinutes(1)));

            await partitionManager.ClaimOwnershipAsync(new List <PartitionOwnership>()
            {
                originalOwnership
            });

            // ETag must have been set by the partition manager.

            var originalLastModifiedTime = originalOwnership.LastModifiedTime;
            var originalETag             = originalOwnership.ETag;

            await partitionManager.UpdateCheckpointAsync(new Checkpoint
                                                         ("eventHubName", "consumerGroup", "ownerIdentifier", "partitionId", 10, 20));

            // Make sure the ownership has changed, even though the instance should be the same.

            var storedOwnership = await partitionManager.ListOwnershipAsync("eventHubName", "consumerGroup");

            Assert.That(storedOwnership, Is.Not.Null);
            Assert.That(storedOwnership.Count, Is.EqualTo(1));
            Assert.That(storedOwnership.Single(), Is.EqualTo(originalOwnership));

            Assert.That(originalOwnership.Offset, Is.EqualTo(10));
            Assert.That(originalOwnership.SequenceNumber, Is.EqualTo(20));
            Assert.That(originalOwnership.LastModifiedTime, Is.GreaterThan(originalLastModifiedTime));
            Assert.That(originalOwnership.ETag, Is.Not.EqualTo(originalETag));
        }
        public async Task CheckpointUpdateFailsWhenOwnerChanges()
        {
            var partitionManager  = new InMemoryPartitionManager();
            var originalOwnership = new PartitionOwnership
                                        ("eventHubName", "consumerGroup", "ownerIdentifier1", "partitionId", offset: 1, sequenceNumber: 2, lastModifiedTime: DateTimeOffset.UtcNow);

            await partitionManager.ClaimOwnershipAsync(new List <PartitionOwnership>()
            {
                originalOwnership
            });

            // ETag must have been set by the partition manager.

            var originalLastModifiedTime = originalOwnership.LastModifiedTime;
            var originalETag             = originalOwnership.ETag;

            await partitionManager.UpdateCheckpointAsync(new Checkpoint
                                                         ("eventHubName", "consumerGroup", "ownerIdentifier2", "partitionId", 10, 20));

            // Make sure the ownership hasn't changed.

            var storedOwnership = await partitionManager.ListOwnershipAsync("eventHubName", "consumerGroup");

            Assert.That(storedOwnership, Is.Not.Null);
            Assert.That(storedOwnership.Count, Is.EqualTo(1));
            Assert.That(storedOwnership.Single(), Is.EqualTo(originalOwnership));

            Assert.That(originalOwnership.OwnerIdentifier, Is.EqualTo("ownerIdentifier1"));
            Assert.That(originalOwnership.Offset, Is.EqualTo(1));
            Assert.That(originalOwnership.SequenceNumber, Is.EqualTo(2));
            Assert.That(originalOwnership.LastModifiedTime, Is.EqualTo(originalLastModifiedTime));
            Assert.That(originalOwnership.ETag, Is.EqualTo(originalETag));
        }
        public async Task OwnershipClaimSucceedsWhenETagIsValid()
        {
            var partitionManager = new InMemoryPartitionManager();
            var ownershipList    = new List <PartitionOwnership>();
            var firstOwnership   =
                new PartitionOwnership
                (
                    "namespace",
                    "eventHubName",
                    "consumerGroup",
                    "ownerIdentifier",
                    "partitionId",
                    offset: 1
                );

            ownershipList.Add(firstOwnership);

            await partitionManager.ClaimOwnershipAsync(ownershipList);

            // ETag must have been set by the partition manager.

            var eTag = firstOwnership.ETag;

            ownershipList.Clear();

            var secondOwnership =
                new PartitionOwnership
                (
                    "namespace",
                    "eventHubName",
                    "consumerGroup",
                    "ownerIdentifier",
                    "partitionId",
                    offset: 2,
                    eTag: eTag
                );

            ownershipList.Add(secondOwnership);

            await partitionManager.ClaimOwnershipAsync(ownershipList);

            IEnumerable <PartitionOwnership> storedOwnership = await partitionManager.ListOwnershipAsync("namespace", "eventHubName", "consumerGroup");

            Assert.That(storedOwnership, Is.Not.Null);
            Assert.That(storedOwnership.Count, Is.EqualTo(1));
            Assert.That(storedOwnership.Single(), Is.EqualTo(secondOwnership));
        }
        public async Task OwnershipClaimFailsWhenETagIsInvalid(string eTag)
        {
            var partitionManager = new InMemoryPartitionManager();
            var ownershipList    = new List <PartitionOwnership>();
            var firstOwnership   =
                new PartitionOwnership
                (
                    "eventHubName",
                    "consumerGroup",
                    "ownerIdentifier",
                    "partitionId",
                    offset: 1
                );

            ownershipList.Add(firstOwnership);

            await partitionManager.ClaimOwnershipAsync(ownershipList);

            ownershipList.Clear();

            var secondOwnership =
                new PartitionOwnership
                (
                    "eventHubName",
                    "consumerGroup",
                    "ownerIdentifier",
                    "partitionId",
                    offset: 2,
                    eTag: eTag
                );

            ownershipList.Add(secondOwnership);

            await partitionManager.ClaimOwnershipAsync(ownershipList);

            var storedOwnership = await partitionManager.ListOwnershipAsync("eventHubName", "consumerGroup");

            Assert.That(storedOwnership, Is.Not.Null);
            Assert.That(storedOwnership.Count, Is.EqualTo(1));
            Assert.That(storedOwnership.Single(), Is.EqualTo(firstOwnership));
        }
        public async Task CheckpointUpdateDoesNotInterfereWithOtherPartitions()
        {
            var partitionManager = new InMemoryPartitionManager();

            var ownership1 = new PartitionOwnership
                                 ("eventHubName", "consumerGroup", "ownerIdentifier", "partitionId1", offset: 1);
            var ownership2 = new PartitionOwnership
                                 ("eventHubName", "consumerGroup", "ownerIdentifier", "partitionId2", offset: 1);

            await partitionManager.ClaimOwnershipAsync(new List <PartitionOwnership>()
            {
                ownership1,
                ownership2
            });

            await partitionManager.UpdateCheckpointAsync(new Checkpoint
                                                         ("eventHubName", "consumerGroup", "ownerIdentifier", "partitionId1", 10, 20));

            Assert.That(ownership1.Offset, Is.EqualTo(10));
            Assert.That(ownership2.Offset, Is.EqualTo(1));
        }
        public async Task FirstOwnershipClaimSucceeds()
        {
            var partitionManager = new InMemoryPartitionManager();
            var ownershipList    = new List <PartitionOwnership>();
            var ownership        =
                new PartitionOwnership
                (
                    "eventHubName",
                    "consumerGroup",
                    "ownerIdentifier",
                    "partitionId"
                );

            ownershipList.Add(ownership);

            await partitionManager.ClaimOwnershipAsync(ownershipList);

            var storedOwnership = await partitionManager.ListOwnershipAsync("eventHubName", "consumerGroup");

            Assert.That(storedOwnership, Is.Not.Null);
            Assert.That(storedOwnership.Count, Is.EqualTo(1));
            Assert.That(storedOwnership.Single(), Is.EqualTo(ownership));
        }
Beispiel #10
0
        public async Task EventProcessorCanReceiveFromCheckpointedEventPosition()
        {
            await using (EventHubScope scope = await EventHubScope.CreateAsync(1))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                {
                    int receivedEventsCount = 0;

                    // Send some events.

                    var  expectedEventsCount        = 20;
                    var  dummyEvent                 = new EventData(Encoding.UTF8.GetBytes("I'm dummy."));
                    long?checkpointedSequenceNumber = default;

                    var partitionId = (await client.GetPartitionIdsAsync()).First();

                    await using (EventHubProducer producer = client.CreateProducer())
                        await using (EventHubConsumer consumer = client.CreateConsumer(EventHubConsumer.DefaultConsumerGroupName, partitionId, EventPosition.Earliest))
                        {
                            // Send a few dummy events.  We are not expecting to receive these.

                            var dummyEventsCount = 30;

                            for (int i = 0; i < dummyEventsCount; i++)
                            {
                                await producer.SendAsync(dummyEvent);
                            }

                            // Receive the events; because there is some non-determinism in the messaging flow, the
                            // sent events may not be immediately available.  Allow for a small number of attempts to receive, in order
                            // to account for availability delays.

                            var receivedEvents = new List <EventData>();
                            var index          = 0;

                            while ((receivedEvents.Count < dummyEventsCount) && (++index < ReceiveRetryLimit))
                            {
                                receivedEvents.AddRange(await consumer.ReceiveAsync(dummyEventsCount + 10, TimeSpan.FromMilliseconds(25)));
                            }

                            Assert.That(receivedEvents.Count, Is.EqualTo(dummyEventsCount));

                            checkpointedSequenceNumber = receivedEvents.Last().SequenceNumber;

                            // Send the events we expect to receive.

                            for (int i = 0; i < expectedEventsCount; i++)
                            {
                                await producer.SendAsync(dummyEvent);
                            }
                        }

                    // Create a partition manager and add an ownership with a checkpoint in it.

                    var partitionManager = new InMemoryPartitionManager();

                    await partitionManager.ClaimOwnershipAsync(new List <PartitionOwnership>()
                    {
                        new PartitionOwnership(client.FullyQualifiedNamespace, client.EventHubName,
                                               EventHubConsumer.DefaultConsumerGroupName, "ownerIdentifier", partitionId,
                                               sequenceNumber: checkpointedSequenceNumber, lastModifiedTime: DateTimeOffset.UtcNow)
                    });

                    // Create the event processor manager to manage our event processors.

                    var eventProcessorManager = new EventProcessorManager
                                                (
                        EventHubConsumer.DefaultConsumerGroupName,
                        client,
                        partitionManager,
                        onProcessEvents: (partitionContext, events, cancellationToken) =>
                    {
                        // Make it a list so we can safely enumerate it.

                        var eventsList = new List <EventData>(events ?? Enumerable.Empty <EventData>());

                        if (eventsList.Count > 0)
                        {
                            Interlocked.Add(ref receivedEventsCount, eventsList.Count);
                        }
                    }
                                                );

                    eventProcessorManager.AddEventProcessors(1);

                    // Start the event processors.

                    await eventProcessorManager.StartAllAsync();

                    // Make sure the event processors have enough time to stabilize and receive events.

                    await eventProcessorManager.WaitStabilization();

                    // Stop the event processors.

                    await eventProcessorManager.StopAllAsync();

                    // Validate results.

                    Assert.That(receivedEventsCount, Is.EqualTo(expectedEventsCount));
                }
            }
        }