.net core 如何将EventProcessorClient配置为仅读取特定分区键(而不是分区id)的事件?

.net core 如何将EventProcessorClient配置为仅读取特定分区键(而不是分区id)的事件?,.net-core,azure-eventhub,azure-sdk-.net,.net Core,Azure Eventhub,Azure Sdk .net,我有一个带有2个分区的事件中心,并使用以下代码使用不同的分区键(基于上的文档)向它发送事件。我正在使用.NET的Azure.Messaging.EventHubs库(使用.NET core 3.1) 如您所见,我发送了第一批带有2个事件(使用分区键作为MyPartitionA),第二批带有2个事件(使用分区键作为MyPartitionB)。有趣的是,来自两个分区键的事件进入了同一个分区(即事件中心上的分区0) 在接收端,我正在尝试使用位于的代码示例,如下所示(我正在使用.NET的Azure.Me

我有一个带有2个分区的事件中心,并使用以下代码使用不同的分区键(基于上的文档)向它发送事件。我正在使用.NET的Azure.Messaging.EventHubs库(使用.NET core 3.1)

如您所见,我发送了第一批带有2个事件(使用分区键作为MyPartitionA),第二批带有2个事件(使用分区键作为MyPartitionB)。有趣的是,来自两个分区键的事件进入了同一个分区(即事件中心上的分区0)

在接收端,我正在尝试使用位于的代码示例,如下所示(我正在使用.NET的Azure.Messaging.EventHubs.Processor库。)

然而,我在上面的代码中找不到只接收给定分区(比如MyPartitionA)的事件而不接收其他分区(比如MyPartitionB)的事件的方法

  • 是否可以注册处理器以接收基于特定分区键(而不是分区id)的事件
  • 如果分区键为MyPartitionA和MyPartitionB的事件都被发送到事件中心中的分区0,那么是否仍然可以只接收单个分区键(例如MyPartitionA)的事件,而不接收不具有相同分区键的其他事件,即使它们可能位于事件中心上的同一分区中

  • EventHubs是一种高吞吐量的持久流,提供流级语义(与服务总线相比)

    现在来回答您的问题,您希望根据事件的属性筛选事件—事件级操作—不是流级操作

    没有直接的方法来实现您的需求

    这种方法是为自己实现定制解决方案——从EventHub(事件流)中提取事件,并有一个中间进程t0按PartitionKey进行过滤,然后将它们推送到另一个事件中心或替代机制,以便相应地使用它

    或者,如果您正在考虑使用服务总线(如果这符合您的要求),则您可以参考以下内容:

    分区键属性将用于标识分区 当会话id为时,消息必须存储在队列中 未设置消息的属性

    您可以使用AcceptMessageSession([PartitionKey])从特定分区键或会话ID接收消息

    参考:


    qc=

    您不能使用SDK中的任何客户端读取基于分区键的事件

    分区键是一个合成概念,在事件发布后不会保留该概念。当您使用分区键发布时,该键将被散列,结果值用于选择要将事件路由到的分区;其目的是确保相关事件路由到同一个分区,但不需要了解选择了哪个分区,也不提供任何公平分配的保证

    要完成您希望执行的筛选,您需要将分区键存储为事件上的,然后将该值用作
    ProcessEventAsync
    处理程序中的筛选器。请注意,您将从所有分区接收所有事件-这是
    EventProcessorClient
    的主要目标


    我认为我们对应用程序场景的上下文了解不够,无法帮助确定最佳方法,但根据我们所知,我建议考虑另一种方法。由于您似乎需要显式地读取一组事件,因此使用已知分区的Id(而不是键)发布到该分区可能会有所帮助。然后,您将能够使用该方法以独占方式从该分区读取事件。当然,这需要您明确控制在应用程序中发布其他事件的位置,以确保它们被路由到第二个分区。

    什么是qc,以及它与上面代码中的EventProcessorClient有何关系?你能详细解释一下吗?@Raghu-有点混乱。更新了我的答案。:)
    await using (var producer = new EventHubProducerClient(connectionString, eventHubName))
    {
        using EventDataBatch eventBatch = await producer.CreateBatchAsync(new CreateBatchOptions() { PartitionKey = "MyPartitionA" });
    
        eventBatch.TryAdd(new EventData(Encoding.UTF8.GetBytes("First")));
        eventBatch.TryAdd(new EventData(Encoding.UTF8.GetBytes("Second")));
        await produce.SendAsync(eventBatch);
    
        using EventDataBatch eventBatch2 = await producer.CreateBatchAsync(new CreateBatchOptions() { PartitionKey = "MyPartitionB" });
    
        eventBatch2.TryAdd(new EventData(Encoding.UTF8.GetBytes("Third")));
        eventBatch2.TryAdd(new EventData(Encoding.UTF8.GetBytes("Fourth")));
    
        await producer.SendAsync(eventBatch2);
    }
    
    async Task processEventHandler(ProcessEventArgs eventArgs)
    {
        try
        {
            // Perform the application-specific processing for an event
            await DoSomethingWithTheEvent(eventArgs.Partition, eventArgs.Data);
        }
        catch
        {
            // Handle the exception from handler code
        }
    }
    
    async Task processErrorHandler(ProcessErrorEventArgs eventArgs)
    {
        try
        {
            // Perform the application-specific processing for an error
            await DoSomethingWithTheError(eventArgs.Exception);
        }
        catch
        {
            // Handle the exception from handler code
        }   
    }
    
    private async Task ProcessUntilCanceled(CancellationToken cancellationToken)
    {
        var storageClient = new BlobContainerClient(storageConnectionString, blobContainerName);
        var processor = new EventProcessorClient(storageClient, consumerGroup, eventHubsConnectionString, eventHubName);
    
        processor.ProcessEventAsync += processEventHandler;
        processor.ProcessErrorAsync += processErrorHandler;
        
        await processor.StartProcessingAsync();
        
        try
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                await Task.Delay(TimeSpan.FromSeconds(1));
            }
            
            await processor.StopProcessingAsync();
        }
        finally
        {
            // To prevent leaks, the handlers should be removed when processing is complete
            processor.ProcessEventAsync -= processEventHandler;
            processor.ProcessErrorAsync -= processErrorHandler;
        }
    }
    
    var partitionlistener = qc.AcceptMessageSession("MyPartitionA");
    var message = partitionlistener.Receive();