简体   繁体   English

服务总线队列的多个客户中的取消令牌处理

[英]Cancellation token processing in multiple customers of Service Bus Queue

I have configurable count of Server Bus queue consumers in a single process. 我可以在单个进程中配置服务器总线队列使用者的数量。 The code uses ReceiveAsync method of QueueClient class and it invokes QueueClient.Close on cancellation. 该代码使用QueueClient类的ReceiveAsync方法,并在取消时调用QueueClient.Close

It works pretty well but it turned out that there is some issue with closing QueueClient - only one client ends immediately, all others hang until serverWaitTime timeout expires. 它工作得很好,但事实证明关闭QueueClient存在一些问题 - 只有一个客户端立即结束,所有其他客户端都会挂起,直到serverWaitTime超时到期。

Look at the code and its output: 查看代码及其输出:

using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.ServiceBus.Messaging;

public class Program
{
    private static void Main()
    {
        CancellationTokenSource source = new CancellationTokenSource();
        var cancellationToken = source.Token;
        var logger = new Logger();

        Task.Run(() =>
        {
            Task.Delay(TimeSpan.FromSeconds(10)).Wait();
            source.Cancel();
            logger.Log("Cancellation requested.");
        });

        string connectionString = "...";
        string queueName = "...";

        var workers = Enumerable.Range(1, 3).Select(i => new Worker(connectionString, queueName, logger));
        var tasks = workers.Select(worker => Task.Run(() => worker.RunAsync(cancellationToken), cancellationToken)).ToArray();
        Task.WaitAll(tasks);
        logger.Log("The end.");
    }
}

class Worker
{
    private readonly Logger _logger;
    private readonly QueueClient _queueClient;

    public Worker(string connectionString, string queueName, Logger logger)
    {
        _logger = logger;
        _queueClient = QueueClient.CreateFromConnectionString(connectionString, queueName);
    }

    public async Task RunAsync(CancellationToken cancellationToken)
    {
        _logger.Log($"Worker {GetHashCode()} started.");
        using (cancellationToken.Register(() => _queueClient.Close()))
            while (!cancellationToken.IsCancellationRequested)
            {
                try
                {
                    var message = await _queueClient.ReceiveAsync(TimeSpan.FromSeconds(20));
                    _logger.Log($"Worker {GetHashCode()}: Process message {message.MessageId}...");
                }
                catch (OperationCanceledException ex)
                {
                    _logger.Log($"Worker {GetHashCode()}: {ex.Message}");
                }
            }
        _logger.Log($"Worker {GetHashCode()} finished.");
    }
}

class Logger
{
    private readonly Stopwatch _stopwatch;

    public Logger()
    {
        _stopwatch = new Stopwatch();
        _stopwatch.Start();
    }

    public void Log(string message) => Console.WriteLine($"{_stopwatch.Elapsed}: {message}");
}

Output: 输出:

00:00:00.8125644: Worker 12547953 started.
00:00:00.8127684: Worker 45653674 started.
00:00:00.8127314: Worker 59817589 started.
00:00:10.4534961: Cancellation requested.
00:00:11.4912900: Worker 45653674: The operation cannot be performed because the entity has been closed or aborted.
00:00:11.4914054: Worker 45653674 finished.
00:00:22.3242631: Worker 12547953: The operation cannot be performed because the entity has been closed or aborted.
00:00:22.3244501: Worker 12547953 finished.
00:00:22.3243945: Worker 59817589: The operation cannot be performed because the entity has been closed or aborted.
00:00:22.3252456: Worker 59817589 finished.
00:00:22.3253535: The end.

So as you can see the worker 45653674 stopped immediately but two others stopped only 10 seconds later. 如您所见,工作人员45653674立即停止了工作,而另外两个仅在10秒后停止了工作。

I found some helpful information in this article: https://developers.de/blogs/damir_dobric/archive/2013/12/03/service-bus-undocumented-scaling-tips-amp-tricks.aspx . 我在本文中找到了一些有用的信息: https//developers.de/blogs/damir_dobric/archive/2013/12/03/service-bus-undocumented-scaling-tips-amp-tricks.aspx The issue goes away if each queue client works via its own physical connection. 如果每个队列客户端通过自己的物理连接工作,问题就会消失。

So to fix the issue it's necessary to replace the following code: 因此,要解决此问题,必须替换以下代码:

_queueClient = QueueClient.CreateFromConnectionString(connectionString, queueName);

with

var factory = MessagingFactory.CreateFromConnectionString(connectionString);
_queueClient = factory.CreateQueueClient(queueName);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 多个发件人的Azure服务总线队列授权 - Azure Service Bus Queue Authorization for Multiple Senders Azure 服务总线触发器未同时处理基于 session 的队列 - Azure Service Bus Trigger is not processing session based queue concurrently 在Azure Service Bus队列中处理消息处理的选项 - options for handling message processing in azure service bus queue Azure Service Bus队列最大批量更新消息锁定以进行批处理 - Azure Service Bus Queue Maximum Renewal of Message Lock for Batch Processing Azure Service Bus Queue并行异步处理消息 - Azure Service Bus Queue processing messages asynchronously in parallel Azure 服务总线 - 创建队列的授权令牌签名无效错误 - Azure Service Bus - Invalid authorization token signature error for queue creation Azure服务总线队列 - Azure Service Bus Queue 同一服务总线队列消息多次运行的Azure函数 - Azure function running multiple times for the same service bus queue message 带有服务总线的 Azure 函数:如果消息处理出现问题,如何将消息保留在队列中? - Azure functions with service bus: How to keep a message in the queue if something goes wrong with its processing? 当带有服务总线队列的辅助角色完成处理时,您如何通知? - How do you notify when a worker role with service bus queue completes it's processing?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM