Skip to content

Files

Latest commit

 

History

History
 
 

WorkflowCore.Sample17

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

Saga transaction with compensation sample

Illustrates how to encapsulate a sequence of steps within a saga transaction and specify compensation steps for each.

In the sample, Task2 will throw an exception, then UndoTask2 and UndoTask1 will be triggered.

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"));

Retry policy for failed saga transaction

This particular example will retry the saga every 5 seconds, but you could also simply fail completely, and process a master compensation task for the whole saga.

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"));

Compensate entire saga transaction

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

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

Passing parameters to compensation steps

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