【问题标题】:Where to catch exceptions in an asynchronous Azure function在异步 Azure 函数中捕获异常的位置
【发布时间】:2018-06-16 04:40:17
【问题描述】:

我已经设置了一个 Azure 函数,我希望它异步运行,因为我希望我的队列中有成百上千/更多的消息将同时出队,所以我已经实现了它下面(也许有更好的方法)。还是我需要担心在函数中异步运行代码?

如果队列中的数千条消息一次全部出列,Azure 会同时处理数千个这样的函数吗?这个 Azure 函数article 说一次只能运行几百个

在哪里放置 try catch 语句的最佳位置?在围绕我的逻辑的异步调用内部还是在异步调用外部(如我的代码)?还是有关系?

public static class CancelEvent
{
    [FunctionName("CancelEvent")] 
    public static async void RunAsync([ServiceBusTrigger("canceleventqueue", AccessRights.Manage, Connection = "service_bus_key")]string myQueueItem, TraceWriter log, ExecutionContext context)
    {
        try
        {
            await Task.Run(() => Processor.ProcessAsync());
        }
        catch(Exception ex)
        {
        }
     }
}

public class Processor
{
    public static void ProcessAsync()
    {
        // do the work
    }
}

【问题讨论】:

    标签: c# azure asynchronous exception-handling azure-functions


    【解决方案1】:

    TLDR;不要将 Azure Functions 构建为异步的。

    在我最近使用 azure 函数的经验中,我发现最好不要将我的函数构建为异步的。

    在我的情况下,我使用 ServiceBusTrigger 接收消息,然后等待处理方法,并且感到困惑的是,当冒泡异常时,它不会在 azure 门户中显示为失败,也不会捕获Application Insights 帐户中的异常详细信息,也不会正确放弃或死信消息。我只会通过转到存储帐户中的 files\eventlog.xml 部分来发现异常详细信息,在该部分中我会发现有关未处理异常的投诉,从而使功能陷入困境。

    花了一天的时间自己进行完整的 try/catch 和处理 message.Abandon() 和 message.Deadletter() 逻辑以及手动记录所有 AppInsights 遥测数据后,我发现根本不做异步并且冒泡出异常(在第一次执行错误报告或处理逻辑之后)导致了我期望平台之外的所有行为。

    门户中函数的“运行历史记录”正确显示了通过和失败的执行,并捕获了所有异常详细信息。

    这是一个警示故事,可让您的 Azure 函数保持静态、同步和简单。他们设计的消息处理特性应该已经足够异步了。

    【讨论】:

      【解决方案2】:

      在对同步方法的调用周围添加await Task.Run 没有多大意义。努力使ProcessAsync 真正异步(返回Task 和非阻塞)。

      所以更好的选择(注意这两种方法都返回Task):

      [FunctionName("CancelEvent")] 
      public static async Task RunAsync([ServiceBusTrigger("canceleventqueue", AccessRights.Manage, Connection = "service_bus_key")]string myQueueItem, TraceWriter log, ExecutionContext context)
      {
          try
          {
              await Processor.ProcessAsync();
          }
          catch (Exception ex)
          {
              // Try catch will work fine 
          }
      }
      
      public class Processor
      {
          public static async Task ProcessAsync()
          {
              // do the work
          }
      }
      

      还有更糟糕的选择,但也是可行的:

      [FunctionName("CancelEvent")] 
      public static void RunAsync([ServiceBusTrigger("canceleventqueue", AccessRights.Manage, Connection = "service_bus_key")]string myQueueItem, TraceWriter log, ExecutionContext context)
      {
          try
          {
              Processor.Process();
          }
          catch (Exception ex)
          {
              // Try catch will work fine 
          }
      }
      
      public class Processor
      {
          public static void Process()
          {
              // do the work
          }
      }
      

      Azure 将在这两种情况下并行运行多个执行。只是第一个选项在资源使用上会更加精简。

      并非所有消息都会一次处理,但 Azure 会根据一些内部扩展逻辑扩展并行执行的数量。

      【讨论】:

      • 嗨,米哈伊尔。是否有必要使这个函数异步或它调用的任何方法异步?我只是调用一个数据库行,获取一个值并发送一封电子邮件,方法'Process()'中没有真正长时间运行的逻辑。通过将异步调用保留在函数或方法“Process()”中,我是否会获得任何速度优势
      • I/O 操作(如数据库调用和发送电子邮件)从异步中获益最多。但你不必这样做。
      • 在处理器类中将“异步”添加到方法“ProcessAsync()”时遇到问题。当我添加“异步”时,我得到一条智能绿线,上面写着“异步方法缺少等待并将同步运行”,它希望我将所有内容都设为非异步。我将发布我所有的代码并在上面进行编辑
      • 是的,只是添加关键字没有帮助,它必须一直异步。 async需要学一点,怕是没办法把SO cmets里的所有细节都解释清楚……
      猜你喜欢
      • 2020-08-24
      • 2019-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-12
      • 2013-04-20
      • 1970-01-01
      相关资源
      最近更新 更多