簡體   English   中英

當一個分區在 Azure 事件中心處於活動狀態時,如何禁用其他分區以停止接收消息

[英]How to disable other partitions to stop receiving messages when one partition is active in Azure event hubs

我有一個安裝在 3 個不同服務器上的應用程序。這個應用程序訂閱了一個事件中心。 此事件中心有 8 個分區。 所以當我在所有 3 台機器上啟動我的應用程序時,所有分區在所有 3 台機器上隨機初始化。

說是這樣的:

VM1:分區 0,1,2
VM2:分區 3,4
VM3:分區 5、6、7

所有這些分區都在不斷地接收消息。 這些消息需要一個接一個地處理。 現在我的要求是,在一台機器/服務器中,我想一次只接收一條消息(無論初始化了多少個分區)。 VM1、VM2、VM3 也可以並行運行。

一個場景是,在一台機器上,比如 VM1,我通過分區 0 收到了一條消息。現在正在處理該消息,通常需要 15 分鍾。 在這 15 分鍾內,我不希望分區 1 或分區 2 在前一個完成之前接收任何新消息。 一旦前面的消息處理完成,那么 3 個分區中的任何一個都准備好接收新消息。 一旦任何分區收到另一條消息,其他分區不應收到任何消息。

我使用的代碼是這樣的:

public class SimpleEventProcessor : IEventProcessor
{
    public Task CloseAsync(PartitionContext context, CloseReason reason)
    {
       Console.WriteLine($"Processor Shutting Down. Partition '{context.PartitionId}', Reason: '{reason}'.");
       return Task.CompletedTask;
    }

    public Task OpenAsync(PartitionContext context)
    {
       Console.WriteLine($"SimpleEventProcessor initialized. Partition: '{context.PartitionId}'");
       return Task.CompletedTask;
     }

    public Task ProcessErrorAsync(PartitionContext context, Exception error)
    {
       Console.WriteLine($"Error on Partition: {context.PartitionId}, Error: {error.Message}");
       return Task.CompletedTask;
    }

    public Task ProcessEventsAsync(PartitionContext context, IEnumerable<EventData> messages)
    {
       foreach (var eventData in messages)
       {
          var data = Encoding.UTF8.GetString(eventData.Body.Array, eventData.Body.Offset, eventData.Body.Count);
          Console.WriteLine($"Message received. Partition: '{context.PartitionId}', Data: '{data}'");
          DoSomethingWithMessage(); // typically takes 15-20 mins to finish this method.
       }
       return context.CheckpointAsync();
    }
} 

這可能嗎?

PS:我必須使用事件中心,別無選擇。

您可以通過對靜態鎖對象進行互斥來實現這一點。

    public Task ProcessEventsAsync(PartitionContext context, IEnumerable<EventData> messages)
    {
        lock (lockObj)
        {
            foreach (var eventData in messages)
            {
                var data = Encoding.UTF8.GetString(eventData.Body.Array, eventData.Body.Offset, eventData.Body.Count);
                Console.WriteLine($"Message received. Partition: '{context.PartitionId}', Data: '{data}'");
                DoSomethingWithMessage(); // typically takes 15-20 mins to finish this method.
            }

            return context.CheckpointAsync();
        }
    }

不要忘記將 EventProcessorOptions.MaxBatchSize 設置為 1,如下所示。

var epo = new EventProcessorOptions
{
    MaxBatchSize = 1
};

await eventProcessorHost.RegisterEventProcessorAsync<MyProcessorHost>(epo);

帶有下游代理的完整處理器代碼。

public class SampleEventProcessor : IEventProcessor
{
    public Task OpenAsync(PartitionContext context)
    {
        Console.WriteLine($"Opened partition {context.PartitionId}");
        return Task.FromResult<object>(null);
    }

    public Task CloseAsync(PartitionContext context, CloseReason reason)
    {
        Console.WriteLine($"Closed partition {context.PartitionId}");
        return Task.FromResult<object>(null);
    }

    public async Task ProcessEventsAsync(PartitionContext context, IEnumerable<EventData> messages)
    {
        foreach (var eventData in messages)
        {
            // Process the mesasage in downstream agent.
            await DownstreamAgent.ProcessEventAsync(eventData);

            // Checkpoint current position.
            await context.CheckpointAsync();
        }
    }

    public Task ProcessErrorAsync(PartitionContext context, Exception error)
    {
        Console.WriteLine($"Partition {context.PartitionId} - {error.Message}");
        return Task.CompletedTask;
    }
}

public class DownstreamAgent
{
    const int DegreeOfParallelism = 1;

    static SemaphoreSlim threadSemaphore = new SemaphoreSlim(DegreeOfParallelism, DegreeOfParallelism);

    public static async Task ProcessEventAsync(EventData message)
    {
        // Wait for a spot so this message can get processed.
        await threadSemaphore.WaitAsync();

        try
        {
            // Process the message here
            var data = Encoding.UTF8.GetString(message.Body.Array);
            Console.WriteLine(data);
        }
        finally
        {
            // Release the semaphore here so that next message waiting can be processed.
            threadSemaphore.Release();
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM