c# - Azure Function v2 在处理 StorageException 后总是返回内部服务器错误 500

标签 c# error-handling azure-functions

假设您有一个使用表存储的 Azure 函数 (v2),您运行但具有 SomePartitionKey/SomeRowKey 的实体存在(例如,您运行以下两次):

[FunctionName("SomeEntity")]
public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "someentity")] HttpRequest req,
                                            [Table("SomeEntities")] IAsyncCollector<SomeEntity> collector,
                                            ILogger logger)
{

    try
    {
        SomeEntity se = new SomeEntity()
        {
                PartitionKey = "SomePartitionKey",
                RowKey = "SomeRowKey"
        };
        await collector.AddAsync(se);
        await collector.FlushAsync();

        return new OkResult();
    }
    catch (Microsoft.WindowsAzure.Storage.StorageException e)
    {
        logger.LogError("There was an error processing the request.", e);
        return new StatusCodeResult(409);
    }
}

当它运行并且实体已经存在时,如预期的那样,它会抛出 StorageException。我的问题是,即使我捕捉到异常并尝试返回 StatusCodeResult(409),发送到客户端的实际响应始终是内部服务器错误 (500)。

我的问题是:
a) 这是函数清理逻辑的结果,它试图在收集器上再次调用 FlushAsync(),导致未处理的 StorageException,从而导致内部服务器错误 (500)。 b) 如果 a) 是,是否有可能避免这种情况?
c) 除了首先检查实体是否存在之外,对于这种情况有什么最佳实践吗?

最佳答案

Azure Functions NuGet 包的一大优点是它们支持源链接。确保你有 Enable Source Link support检查你的 Visual Studio 选项,你将能够准确地看到他们的代码在做什么。函数应用运行后,您可以选择在抛出任何 CLR 异常时中断。

如果执行此操作,您会看到异常从 FlushAsync 中按预期抛出。 ,您的代码正在捕获它,并返回 409 结果。然后,在你的函数返回后,再次抛出相同的异常(因为 FlushAsync 在你的函数之外再次被调用),它被捕获并抛出一个包装器异常,消息为 Error while handling parameter collector after function returned。 ,它又被捕获并抛出包装器异常并显示消息 Exception while executing function: SomeEntity ,它又被捕获,并且只向客户端返回一个普通的旧 500 错误。

所以:

a) Is this the result of cleanup logic of the Function attempting to call FlushAsync() again on the collector resulting in an unhandled StorageException which causes an Internal Server Error (500).

是的。如果启用源链接支持和抛出时中断,则可以直接通过 Azure Functions 运行时进行调试并看到这种情况发生。

b) If yes to a), is it possible to prevent this?

c) Aside from checking if the entity exists first is there any best practice for this scenario?

推荐check-then-insert。你最终会遇到竞争条件。

来自 the docs :

This output binding does not support updating existing entities. Use the TableOperation.Replace operation from the Azure Storage SDK to update an existing entity.

作为一般规则,任何给定服务的 Azure Functions 绑定(bind)都是针对简单用例的。对于 Azure 存储表,简单的用例是插入实体。

但是,您始终可以自己使用存储 SDK。无论如何,这几乎就是绑定(bind)为您所做的。此绑定(bind)也进行一些批处理,但如果您需要的话,这并不难实现。

你也可以做一个“中途”:让表绑定(bind)绑定(bind)到 CloudTable而不是 IAsyncCollector<SomeEntity> .这样您将自动使用适当的连接字符串;你只需要写你自己的TableOperation.InsertOrReplace代码。

关于c# - Azure Function v2 在处理 StorageException 后总是返回内部服务器错误 500,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55292436/

相关文章:

rest - REST-API V2返回没有详细信息的服务器错误

azure - 当函数发布到云时,停止在现有 Blob 上触发 Azure Blob 触发器函数

azure - 如何在 Azure Function App 中配置队列触发器的队列名称

c# - 临时为选定范围着色边框

c# - 在两个类实例之间动态复制某些属性

c++ - 输入7个字母单词,输出7位数电话号码

c - C 中错误记录/通知库的设计注意事项

c# - 将 XML 元素读取到 ListView - 我如何将两个变量传递给方法

c# - 入口控件扩展到 StackLayout 容器之外

azure - ServiceBus Dequeue 触发消息在 azure 中解码 Golang 自定义处理程序 : message format