在队列触发的Azure Webjobs中,可以在webjob函数失败之后但在中毒之前修改Azure存储队列消息吗?

时间:2018-08-05 02:30:34

标签: azure azure-webjobs azure-webjobssdk azure-storage-queues

我的Azure webjobs中有队列触发的函数。当然,正常的行为是当函数失败MaxDequeueCount次时,将消息放入适当的中毒队列。我想修改错误消息之后,但之前插入毒物队列。示例:

初始消息:

{ "Name":"Tom", "Age", 30" }

在失败后,我想按以下方式修改消息,然后将修改后的消息插入毒物队列:

{ "Name":"Tom", "Age", 30", "ErrorMessage":"Unable to find user" }

可以做到吗?

2 个答案:

答案 0 :(得分:0)

根据Webjobs文档,在尝试处理消息5次失败后,消息将被放入中毒队列:

  

SDK将调用一个函数最多5次以处理队列消息。   如果第五次尝试失败,则该消息将移至中毒队列。的   重试的最大次数是可配置的。

来源:https://github.com/Azure/azure-webjobs-sdk/wiki/Queues#poison

这是自动行为。但是,您仍然可以在WebJobs函数代码中处理异常(这样,异常不会离开您的函数,并且不会触发自动检测有害消息),并使用输出绑定将修改后的消息放入有害队列。

另一种选择是检查dequeueCount属性,该属性指示尝试处理该消息的次数。

  

您可以获得获取消息的次数   通过添加一个名为dequeueCount的int参数到您的处理   功能。然后,您可以在功能代码中检查出队计数,然后   当数量超过一个时,执行您自己的毒药消息处理   阈值,如以下示例所示。

public static void CopyBlob(
        [QueueTrigger("copyblobqueue")] string blobName, int dequeueCount,
        [Blob("textblobs/{queueTrigger}", FileAccess.Read)] Stream blobInput,
        [Blob("textblobs/{queueTrigger}-new", FileAccess.Write)] Stream blobOutput,
        TextWriter logger)
    {
        if (dequeueCount > 3)
        {
            logger.WriteLine("Failed to copy blob, name=" + blobName);
        }
        else
        {
        blobInput.CopyTo(blobOutput, 4096);
        }
    }

(也来自上面的链接)。

您的函数签名可能看起来像这样

public static void ProcessQueueMessage(
            [QueueTrigger("myqueue")] CloudQueueMessage message,
            [Queue("myqueue-poison")] CloudQueueMessage poisonMessage,
            TextWriter logger)

答案 1 :(得分:0)

默认的最大重试时间为5。您还可以使用Queues.MaxDequeueCount实例的属性JobHostConfiguration()自行设置此值,如下所示:

static void Main(string[] args)
{
    var config = new JobHostConfiguration();            
    config.Queues.MaxDequeueCount = 5; // set the maximum retry time
    var host = new JobHost(config);
    host.RunAndBlock();
} 

然后,当达到最大重试时间时,您可以更新失败的队列消息。您可以指定一个不存在的Blob容器来强制重试机制。如下代码:

public static void ProcessQueueMessage([QueueTrigger("queue")] CloudQueueMessage message, [Blob("container/{queueTrigger}", FileAccess.Read)] Stream myBlob, ILogger logger)
 {
       string yourUpdatedString = "ErrorMessage" + ":" + "Unable to find user";
       string str1 = message.AsString;
       if (message.DequeueCount == 5) // here, the maximum retry time is set to 5
       {
                message.SetMessageContent(str1.Replace("}", "," + yourUpdatedString + "}"));   // modify the failed message here
       }
       logger.LogInformation($"Blob name:{message} \n Size: {myBlob.Length} bytes");
 }

完成上述操作后,您可以在队列毒物中看到更新的队列消息。

已更新:

由于CloudQueueMessage是一个密封的类,所以我们不能继承它。

对于MySpecialPoco消息,可以使用JsonConvert.SerializeObject(message),代码如下:

using  Newtonsoft.Json;

static int number = 0;
 public static void ProcessQueueMessage([QueueTrigger("queue")] object message, [Blob("container/{queueTrigger}", FileAccess.Read)] Stream myBlob, ILogger logger)
        {
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));    
            CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();                
            CloudQueue queue = queueClient.GetQueueReference("queue-poison");// get the poison queue
            CloudQueueMessage msg1 = new CloudQueueMessage(JsonConvert.SerializeObject(message));
            number++;
            string yourUpdatedString = "\"ErrorMessage\"" + ":" + "\"Unable to find user\"";
            string str1 = msg1.AsString;

            if (number == 5)
            {    
                msg1.SetMessageContent(str1.Replace("}", "," + yourUpdatedString + "}"));
                queue.AddMessage(msg1);                  
                number = 0;                   
            }                
            logger.LogInformation($"Blob name:{message} \n Size: {myBlob.Length} bytes");
        }

但是不好的是,原始/更新的队列消息都被写入毒药队列。