Skip to content

joro550/Transactor

Repository files navigation

Transactor

When performing complex operations on a distributed system we usually want a way to perform the operation and rollback when things don't go the way we expect them to go.

This library help with that process, let's say we want to

  • Save a file
  • Update the database
  • Send a message on a queue

First we define our seperate steps with their appropriate rollbacks

public class MyContext : IExecutionContext
{
    public int DatabaseId {get;set;}
}


public class SaveFileStep : AsyncStep<MyContext>
{
    private readonly string _fileName;

    public SaveFileStep(string fileName)
    {
        _fileName = fileName;
    }

    public override Task Execute(CancellationToken cancellationToken = default)
    {
        // save file to directory
        return Task.CompletedTask;
    }

    public override Task RollBack(CancellationToken cancellationToken = default)
    {
        // Delete file?
        return Task.CompletedTask;
    }
}

public class UpdateDatabase : AsyncStep<MyContext>
{
    private readonly DatabaseContext _context;

    public UpdateDatabase(DatabaseContext context)
    {
        _context = context;
    }
    
    public override Task Execute(CancellationToken cancellationToken = default)
    {
        // save item to database
        return Task.CompletedTask;
    }

    public override Task RollBack(CancellationToken cancellationToken = default)
    {
        // Delete record?
        return Task.CompletedTask;
    }
}

public class SendMessage : AsyncStep<MyContext>
{
    private readonly Queue _context;

    public SendMessage(Queue context)
    {
        _context = context;
    }
    
    public override Task Execute(CancellationToken cancellationToken = default)
    {
        // Send message to queue
        return Task.CompletedTask;
    }

    public override Task RollBack(CancellationToken cancellationToken = default)
    {
        // ??
        return Task.CompletedTask;
    }
}

Then we list the steps in an order which we would want to operate, for example here we add the message to the queue last as this operation has no rollback

var fileName = "C:/users/file.txt";
var context = new DatabaseContext();
var queue = new Queue();

var workflow = new WorkflowBuilder<MyContext>()
    .AddStep(new SaveFileOperation(fileName))
    .AddStep(new UpdateDatabase(context))
    .AddStep(new SendMessage(queue))
    .Build();

This now completes each step in order, if one fails then it will replay the tasks that fail.

var result = await workflow.ExecuteAsync();

The result of this method is a type that tells you whether the workflow was a success and the context (in this case it would be MyContext)

public class ExecutionResult<T> where T: IExecutionContext, new()
{
    public bool Success { get; }
    public T Context { get;  }

    private ExecutionResult(bool success, T context)
    {
        Success = success;
        Context = context;
    }
}

About

Workflow execute and rollback system

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages