【问题标题】:Azure Function App Azure Service Bus trigger triggers twiceAzure Function App Azure Service Bus 触发器触发两次
【发布时间】:2020-02-27 14:02:55
【问题描述】:

我正在使用带有服务总线触发器的 Azure 函数应用来读取服务总线并处理服务总线消息的内容。服务总线接收 JSON 序列化对象,然后我将 JSON 消息反序列化回函数应用程序中的对象。但是,由于某种原因,每当有东西被发送到服务总线时,触发器就会触发两次,一次是 JSON 消息,另一次是包含文本“服务总线消息”的消息。

我不知道是什么导致了第二条消息,所以我想出的只是反序列化服务总线消息,当它因“服务总线消息”而失败时,我将捕获异常并忽略它.但是,我认为这不是处理此问题的正确方法,并且 JSON 反序列化中的实际错误将被忽略。处理第二条消息的正确方法是什么?

示例代码:

using Newtonsoft.Json;

public static void Run(string myQueueItem, ILogger log, out SendGridMessage mailMessage)
{
    MyClass myObject = null;
    try
    {
        myObject = JsonConvert.DeserializeObject<MyClass>(myQueueItem);
        // do stuff
    }
    catch (JsonException je)
    {
        // ignore this exception
    }
    catch (Exception e)
    {
        // handle the other exceptions and send an alert
    }
}

编辑:我在原帖中遗漏的一件事是我也有一个 SendGrid 输出。我不明白为什么这会对触发器产生任何影响,这就是我忽略它的原因。但是,我现在添加它以防万一它可能是出于某种奇怪的原因。

编辑 2:添加了突出问题的完整工作代码

// Sender
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.ServiceBus;
using Newtonsoft.Json;

namespace myapp
{
    class Program
    {
        static void Main(string[] args) => MainAsync().GetAwaiter().GetResult();

        static async Task MainAsync()
        {
            string serviceBusConnectionString = "<your servicebus connectionstring>";
            string queueName = "<your queue name>";
            IQueueClient queueClient = new QueueClient(serviceBusConnectionString, queueName);
            string messageBody = JsonConvert.SerializeObject(new Test());
            var message = new Message(Encoding.UTF8.GetBytes(messageBody));
            await queueClient.SendAsync(message);
            await queueClient.CloseAsync();
        }

        class Test
        {
            public string Text { get; set; } = "test";
        }
    }
}
// Receiver
#r "Newtonsoft.Json"

using System;
using System.Threading.Tasks;
using Newtonsoft.Json;

public static void Run(string myQueueItem, ILogger log)
{
    try
    {
        Test test = JsonConvert.DeserializeObject<Test>(myQueueItem);
        log.LogInformation($"C# ServiceBus queue trigger function processed message: {test.Text}");
    }
    catch (Exception e)
    {
        log.LogInformation($"Exception: {e.Message}");
    }
}

class Test
{
    public string Text { get; set; } = "test";
}

结果:

2019-11-04T08:38:10.544 [Information] Executing 'Functions.test' (Reason='This function was programmatically called via the host APIs.', Id=06e10006-baa6-430f-b5db-9a5eae5c154c)
2019-11-04T08:38:10.659 [Information] Exception: Unexpected character encountered while parsing value: S. Path '', line 0, position 0. // This here is caused by "Service bus message"
2019-11-04T08:38:10.659 [Information] Executed 'Functions.test' (Succeeded, Id=06e10006-baa6-430f-b5db-9a5eae5c154c)
2019-11-04T08:39:02.582 [Information] Executing 'Functions.test' (Reason='New ServiceBus message detected on 'test'.', Id=5d7622a7-cc8d-44c9-8720-626fdbb8cabb)
2019-11-04T08:39:02.583 [Information] Trigger Details: MessageId: 13bba779fd524fa1a0098acd6634aded, DeliveryCount: 1, EnqueuedTime: 11/4/2019 8:39:02 AM, LockedUntil: 11/4/2019 8:39:07 AM
2019-11-04T08:39:02.584 [Information] C# ServiceBus queue trigger function processed message: test // This here is the actual message
2019-11-04T08:39:02.584 [Information] Executed 'Functions.test' (Succeeded, Id=5d7622a7-cc8d-44c9-8720-626fdbb8cabb)

【问题讨论】:

  • 不同的问题。
  • @Roihu 您是否对样本中未显示的myQueueItem 进行任何修改?
  • 不,我对myQueueItem 的唯一引用是在我对其进行反序列化时。也许我明天会写一个完整的例子,这样人们就可以自己尝试这种行为。

标签: c# azure servicebus azure-function-app


【解决方案1】:

根据我的测试,触发器不会被触发两次。

namespace ServiceBusTrigger
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static void Run([ServiceBusTrigger("myqueue", Connection = "ServiceBusConnection")]string myQueueItem, ILogger log)
        {
            log.LogInformation($"C# ServiceBus queue trigger function processed message: {myQueueItem}");

            var myMessage = JsonConvert.DeserializeObject<MyMessage>(myQueueItem);

            log.LogInformation($"ID: {myMessage.id}\tContent:{myMessage.content}");
        }
    }
}

手动发送消息,得到如下输出:


Pause Clear Expand

2019-11-04T08:18:56.837 [Information] Executing 'Function1' (Reason='New ServiceBus message detected on 'myqueue'.', Id=7fb37483-b9a3-4c19-baa3-235b419bb585)
2019-11-04T08:18:56.837 [Information] Trigger Details: MessageId: c00a8e41-d883-4620-992f-6b9b4fdae320, DeliveryCount: 1, EnqueuedTime: 11/4/2019 8:18:56 AM, LockedUntil: 11/4/2019 8:19:26 AM
2019-11-04T08:18:56.838 [Information] C# ServiceBus queue trigger function processed message: {"id":"1","content":"abc"}
2019-11-04T08:18:56.838 [Information] ID: 1 Content:abc
2019-11-04T08:18:56.839 [Information] Executed 'Function1' (Succeeded, Id=7fb37483-b9a3-4c19-baa3-235b419bb585)

那么,您能否检查一下您的服务总线生产商,看看是否发送了任何其他消息。

您可以停止您的函数应用,手动发送消息并在门户上查看:

如果一切正常,那么应该只有 1 条活动消息。


更新

【讨论】:

  • 好的,感谢您的示例,我找到了问题所在。 log.LogInformation($"C# ServiceBus queue trigger function processed message: {myQueueItem}"); 在 Run 方法的开头似乎是强制性的。没有它,我所描述的就会发生。
  • @Roihu 不正确。我评论了日志输出。还是只触发了一次。检查更新。
  • 哦,情节变厚了。虽然该行存在(即使已注释掉),但它可以按预期工作。如果实际删除了该行,则会出现问题。我将您的回复标记为答案,因为它使我能够克服这个问题。
  • @JackJia 你也测试过删除线吗?这似乎很奇怪,这应该有什么影响??