Skip to content

v1.6.0

Compare
Choose a tag to compare
@danielgerlag danielgerlag released this 24 Dec 01:59
· 640 commits to master since this release
eb00c95

Workflow Core 1.6.0

  • Added Saga transaction feature
  • Added .CompensateWith feature

Specifying compensation steps for each component of a saga transaction

In this sample, if Task2 throws an exception, then UndoTask2 and UndoTask1 will be triggered.

builder
    .StartWith<SayHello>()
        .CompensateWith<UndoHello>()
    .Saga(saga => saga
        .StartWith<DoTask1>()
            .CompensateWith<UndoTask1>()
        .Then<DoTask2>()
            .CompensateWith<UndoTask2>()
        .Then<DoTask3>()
            .CompensateWith<UndoTask3>()
    )
    .Then<SayGoodbye>();

Retrying a failed transaction

This particular example will retry the entire saga every 5 seconds

builder
    .StartWith<SayHello>()
        .CompensateWith<UndoHello>()
    .Saga(saga => saga
        .StartWith<DoTask1>()
	    .CompensateWith<UndoTask1>()
	.Then<DoTask2>()
	    .CompensateWith<UndoTask2>()
	.Then<DoTask3>()
	    .CompensateWith<UndoTask3>()
	)		
	.OnError(Models.WorkflowErrorHandling.Retry, TimeSpan.FromSeconds(5))
	.Then<SayGoodbye>();

Compensating the entire transaction

You could also only specify a master compensation step, as follows

builder
	.StartWith<SayHello>()
		.CompensateWith<UndoHello>()
	.Saga(saga => saga
		.StartWith<DoTask1>()
		.Then<DoTask2>()
		.Then<DoTask3>()
	)		
        .CompensateWithSequence(comp => comp
            .StartWith<UndoTask1>()
            .Then<UndoTask2>()
	    .Then<UndoTask3>()
        )
	.Then<SayGoodbye>();

Passing parameters

Parameters can be passed to a compensation step as follows

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

Expressing a saga in JSON

A saga transaction can be expressed in JSON, by using the WorkflowCore.Primitives.Sequence step and setting the Saga parameter to true.

The compensation steps can be defined by specifying the CompensateWith parameter.

{
  "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"
    }
  ]
}