假设您有一个使用表存储的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软件包的一大优点是它们启用了源链接。确保已在Visual Studio选项中选中Enable Source Link support
,并且可以准确查看其代码在做什么。一旦功能应用程序运行,您就可以选择在引发任何CLR异常时中断。
如果执行此操作,则会看到FlushAsync
抛出了异常,您的代码正在捕获该异常,并返回409结果。然后,在函数返回之后,再次引发相同的异常(因为在函数外部再次调用了FlushAsync
),该异常被捕获,并且包装器异常与消息Error while handling parameter collector after function returned
一起引发,该消息又被捕获,包装器异常与消息Exception while executing function: SomeEntity
,该消息又被捕获,并且仅向用户返回一个简单的旧500错误。
所以:
是。如果启用“源链接”支持和“抛出时断开”,则可以直接通过Azure Functions运行时进行调试,并观察到这种情况。
我不建议先检查然后插入。您最终将面临比赛条件。
从the docs:
通常,任何给定服务的Azure Functions绑定(bind)都是针对简单用例的。对于Azure存储表,简单的用例只是插入实体。
但是,您始终可以自己使用Storage SDK。无论如何,这几乎就是绑定(bind)为您所做的。该绑定(bind)也进行了一些批处理,但是如果需要的话,实现起来并不难。
您还可以执行“半路”:让Tables绑定(bind)绑定(bind)到CloudTable
而不是IAsyncCollector<SomeEntity>
。这样,您将自动使用适当的连接字符串。您只需要编写自己的TableOperation.InsertOrReplace
代码。
关于c# - 处理的StorageException之后,Azure Function v2始终返回内部服务器错误500,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55292436/