Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/azure/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在持久函数中回滚数据库更改_C#_Azure_Azure Functions_Azure Durable Functions - Fatal编程技术网

C# 在持久函数中回滚数据库更改

C# 在持久函数中回滚数据库更改,c#,azure,azure-functions,azure-durable-functions,C#,Azure,Azure Functions,Azure Durable Functions,假设我有以下编排: [FunctionName("Orchestration")] public static async Task Orchestration_Start([OrchestrationTrigger] DurableOrchestrationContext ctx) { await ctx.CallActivityAsync("Foo"); await ctx.CallActivityAsync("Bar"); await Task.WhenAll(c

假设我有以下编排:

[FunctionName("Orchestration")]
public static async Task Orchestration_Start([OrchestrationTrigger]  DurableOrchestrationContext ctx)
{
    await ctx.CallActivityAsync("Foo");
    await ctx.CallActivityAsync("Bar");
    await Task.WhenAll(ctx.CallActivityAsync("Baz"), ctx.CallActivityAsync("Baz"));
}
我的所有活动都使用Azure SQL数据库,如果任何调用失败,我希望撤消以前活动所做的所有更改-例如,如果对
Baz
的第二次调用引发异常,我希望撤消
Foo
Bar
所做的所有操作,如果第一次
Baz
已完成,我也想撤销它的修改

在非函数应用程序中,我可以使用scope=newtransactionscope()将整个业务流程包装在
块中


这是否适用于潜在的分布式编排,如果不适用,Azure功能框架中是否有类似的机制?或者我需要为每个活动编写一个回滚实现,并在完成每个活动后将更改提交到数据库?

持久函数实现一种最终一致性的机制。这是一个与其他类型的一致性(例如强一致性)完全不同的概念,因为它保证事务最终会完成。这是什么意思

通过使用
TransactionScope
可以确保,如果事务中出现任何错误,将自动执行回滚。在持久功能中,情况并非如此—您没有提供此类功能的自动功能—事实上,如果示例中的第二个活动失败,您将在数据库中存储不一致的数据

要在这种情况下实现事务,您必须尝试/捕获可能的问题并执行逻辑,这将允许您减轻错误:

[FunctionName("Orchestration")]
public static async Task Orchestration_Start([OrchestrationTrigger]  DurableOrchestrationContext ctx)
{
    try 
    {
        await ctx.CallActivityAsync("Foo");
        await ctx.CallActivityAsync("Bar");
        await Task.WhenAll(ctx.CallActivityAsync("Baz"), ctx.CallActivityAsync("Baz"));
    }
    catch(Exception)
    {
        // Do something...
    }  
}
还可以实施重试策略以避免暂时性错误:

public static async Task Run(DurableOrchestrationContext context)
{
    var retryOptions = new RetryOptions(
        firstRetryInterval: TimeSpan.FromSeconds(5),
        maxNumberOfAttempts: 3);

    await ctx.CallActivityWithRetryAsync("FlakyFunction", retryOptions, null);

    // ...
}
然而,重要的是理解持久函数的运行时在出现问题时如何真正管理情况。让我们假设以下代码失败:

[FunctionName("Orchestration")]
public static async Task Orchestration_Start([OrchestrationTrigger]  DurableOrchestrationContext ctx)
{
    await ctx.CallActivityAsync("Foo");
    await ctx.CallActivityAsync("Bar"); // THROWS!
    await Task.WhenAll(ctx.CallActivityAsync("Baz"), ctx.CallActivityAsync("Baz"));
}
如果重播整个编排,第一个活动(传递了“Foo”的活动)将不会再次执行-其状态将存储在存储器中,因此结果将立即可用。运行时在每个活动之后执行一个检查点,因此状态被保留,并且它知道之前在哪里完成

现在,要正确处理一种情况,您必须实现以下算法:

  • 捕获异常时执行手动回滚
  • 如果失败,则将消息推送到队列,然后由了解流程工作原理的人员手动处理
虽然一开始,它看起来像一个大缺陷,但事实上,它是一个完美的解决方案-错误确实会发生,因此避免暂时性错误(使用重试)始终是一个好主意,但如果回滚失败,这清楚地表明系统中存在错误

选择权在你,无论你是否具有很强的一致性,必须处理可伸缩性方面的问题,还是使用更松散的模型,它提供了更好的可伸缩性,但更难使用