Saga 事务

附带补偿的Saga事务

Saga允许您在一个Saga事务中封装一系列步骤,并为每个步骤指定补偿步骤。

在样例中,Task2将抛出一个异常,然后UndoTask2和UndoTask1将被触发。

builder
    .StartWith(context => Console.WriteLine("Begin"))
    .Saga(saga => saga
        .StartWith<Task1>()
            .CompensateWith<UndoTask1>()
        .Then<Task2>()
            .CompensateWith<UndoTask2>()
        .Then<Task3>()
            .CompensateWith<UndoTask3>()
    )
    .OnError(Models.WorkflowErrorHandling.Retry, TimeSpan.FromSeconds(5))
    .Then(context => Console.WriteLine("End"));

失败的Saga事务重试策略

这个特殊的例子将每5秒重试一次传奇,但你也可能完全失败,并为整个传奇处理一个主补偿任务。

builder
    .StartWith(context => Console.WriteLine("Begin"))
    .Saga(saga => saga
        .StartWith<Task1>()
            .CompensateWith<UndoTask1>()
        .Then<Task2>()
            .CompensateWith<UndoTask2>()
        .Then<Task3>()
            .CompensateWith<UndoTask3>()
    )
        .CompensateWith<CleanUp>()
    .Then(context => Console.WriteLine("End"));

整批赔偿交易

您还可以只指定一个主补偿步骤,如下所示

builder
    .StartWith(context => Console.WriteLine("Begin"))
        .Saga(saga => saga
            .StartWith<Task1>()
            .Then<Task2>()
            .Then<Task3>()
    )
        .CompensateWith<UndoEverything>()
    .Then(context => Console.WriteLine("End"));

将参数传递给补偿步骤

可以将参数传递到补偿步骤,如下所示

builder
    .StartWith<SayHello>()
        .CompensateWith<PrintMessage>(compensate => 
        {
            compensate.Input(step => step.Message, data => "undoing...");
        })

用JSON表示一个Saga

通过使用WorkflowCore.Primitives,可以用JSON表示一个saga事务。序列步骤和设置传奇参数为真。

可以通过使用参数指定compensation来定义补偿步骤。

{
  "Id": "Saga-Sample",
  "Version": 1,
  "DataType": "MyApp.MyDataClass, MyApp",
  "Steps": [
    {
      "Id": "Hello",
      "StepType": "MyApp.HelloWorld, MyApp",
      "NextStepId": "MySaga"
    },    
    {
      "Id": "MySaga",
      "StepType": "WorkflowCore.Primitives.Sequence, WorkflowCore",
      "NextStepId": "Bye",
      "Saga": true,
      "Do": [
        [
          {
            "Id": "do1",
            "StepType": "MyApp.Task1, MyApp",
            "NextStepId": "do2",
            "CompensateWith": [
              {
                "Id": "undo1",
                "StepType": "MyApp.UndoTask1, MyApp"
              }
            ]
          },
          {
            "Id": "do2",
            "StepType": "MyApp.Task2, MyApp",
            "CompensateWith": [
              {
                "Id": "undo2-1",
                "NextStepId": "undo2-2",
                "StepType": "MyApp.UndoTask2, MyApp"
              },
              {
                "Id": "undo2-2",
                "StepType": "MyApp.DoSomethingElse, MyApp"
              }
            ]
          }
        ]
      ]
    },    
    {
      "Id": "Bye",
      "StepType": "MyApp.GoodbyeWorld, MyApp"
    }
  ]
}