从MessageSession异步接收消息时处理TimeoutException

时间:2015-05-27 14:24:10

标签: c# azure multitasking servicebus

目前,我的解决方案涉及1个Web和1个Worker角色,通过Azure Service Bus“互相交谈”:

  • Web角色将消息发送到“请求”队列。
  • Worker从“请求”队列中获取消息,执行一些工作并将响应消息发送到“响应”队列,Web角色将从这些队列中获取响应消息。
  • Web角色发送的每条请求消息都必须找到您的响应,这就是为什么我“标记”具有唯一相关标识符的每条请求消息。 Worker从请求中获取此标识符并使​​用它“标记”响应。

最初,我发送一堆邮件:

var messages = tasksForExecution.Select(s =>
            {
                var message = new BrokeredMessage(s);
                message.Properties.Add("action", "submit");
                message.ReplyToSessionId =  Guid.NewGuid().ToString("D");
                return message;
            }).ToList();
var correlationIdentifiers = messages.Select(x => x.ReplyToSessionId).ToList();
messages.ForEach(message => _requestQueueClient.SendAsync(message));

获得回复:

var sessions = correlationIdentifiers
            .Select(x=>_responseQueueClient.AcceptMessageSession(x)).ToList();
var receiveMessageTasks = sessions.Select(session => session.ReceiveAsync()).ToList();
var allReadyTask = Task.WhenAll(receiveMessageTasks).ContinueWith(x =>
            {
                ...extract data from result...
            }
..........
..........
allReadyTask.Wait();

正如您所看到的,我正在创建大量任务,当所有任务完成后,将调用回调来提取一些数据。但是,如果任务中出现异常,会发生什么? - >捕获此异常,并在调用Wait()时将其提供给我们。由于ReceiveAsync()方法的默认超时为1分钟,因此极有可能接收到TimeoutException,因为worker稍后可能会完成其作业,并且队列中不会存在此会话的消息。我发现了许多例子,人们捕捉到这种类型的异常,消费它,再次尝试接收 - 他们给了工人另外一分钟的时间来完成这项工作。我怎样才能在我的场景中实现这一点。谢谢!

1 个答案:

答案 0 :(得分:0)

我发布了我对该问题的解决方案。请参阅上一篇文章以找出变量。

var receiveMessageTasks = sessions.Select(ReceiveMessageAsync).ToList();
var allReadyTask = Task.WhenAll(receiveMessageTasks).ContinueWith(x =>
        {
            ...extract data from result...
        }
allReadyTask.Wait();

其中receiveMessageTasks方法如下:

private async Task<BrokeredMessage> ReceiveMessageAsync(MessageSession session)
    {
        BrokeredMessage message = null;

        // We can specify dead line for processing, but since our worker will return error message if a problem arise,
        // I prefer to wait endlessly
        // var timesToRetry = 0;

        // if Receive operation throws an exception, then message will be null
        while (message == null /* && timesToRetry < 5*/)
        {
            try
            {
                var task = session.ReceiveAsync().ConfigureAwait(false);
                await task;
                message = task.GetAwaiter().GetResult();
                //timesToRetry++;
            }
            catch (Exception e)
            {
                // session was idle for a long time and azure closed it -> renew it
                session = _responseQueueClient.AcceptMessageSession(session.SessionId);
            }
        }
        return message;
    } 

请注意ConfigureAwait(false)Here您可以找到问题的描述:)