.net 中多步骤业务场景的回退方法

Fallback methods for multiple step business scenario in .net

我有一个相当简单的应用程序,我需要一些简化版本的 saga 模式。 这是一种整体类型的应用程序,我只需要获取一堆注入的服务并一个一个地执行这些服务的一些操作。 为简单起见,我们将这些服务称为“步骤”,因此它非常类似于一个多步骤场景,其中每个步骤操作实际上是某个注入服务的一个方法。 那当然很容易。但我想知道使用回退方法进行一些巧妙的错误处理。 假设我有三个服务和三个调用它们的方法。如果第一个失败,我需要在其上触发回退方法。如果第二个失败,我需要从第二个调用回退,然后是第一个。如果第三个失败,我需要从第三步调用回退,然后是第二步,最后是第一步。 所以类似于微服务世界的传奇模式,只是在非分布式应用程序中完成。

使用简单的 try/catch 块轻松编码,如下例所示。我只是在寻找更聪明的方法来做那件事。有关如何将这段代码重构为更易于管理的内容的任何提示?它看起来很糟糕,尤其是如果它发展成十步场景。

我试过 workflow-core 包 (https://github.com/danielgerlag/workflow-core) as well as the Elsa workflows (https://elsa-workflows.github.io/elsa-core/),但它们似乎有点矫枉过正。我不想在我的应用程序中使用完全消息或事件驱动的模型。我只需要他们允许您执行的良好回退机制。

https://dotnetfiddle.net/WRLRy1

public class Program
{
    public static void Main()
    {
        var step1 = new Step1();
        var step2 = new Step2();
        var step3 = new Step3();
        
        try
        {
            step1.DoSomethingInStep1();
        }
        catch
        {
            step1.FallbackFromStep1();
        }
        
        try
        {
            step2.DoSomethingInStep2();
        }
        catch
        {
            step2.FallbackFromStep2();
            step1.FallbackFromStep1();
        }
        
        try
        {
            step3.DoSomethingInStep3();
        }
        catch
        {
            step3.FallbackFromStep3();
            step2.FallbackFromStep2();
            step1.FallbackFromStep1();
        }
    }
}

public class Step1
{
    public void DoSomethingInStep1() {} 
    public void FallbackFromStep1() {}
}

public class Step2
{
    public void DoSomethingInStep2() {} 
    public void FallbackFromStep2() {}
}

public class Step3
{
    public void DoSomethingInStep3() {} 
    public void FallbackFromStep3() {}
}

您可以使用堆栈来保存工作进程中需要的所有回滚步骤。当它出错时,只需运行堆栈中的所有回滚步骤。

这是代码-

    public interface IStep
    {
        public void Do();
        public void Rollback();
    }

    public static class StepHelper
    {
        public static void RunSteps(List<IStep> steps)
        {
            var rollback = new Stack<Action>();

            try
            {
                foreach (var step in steps)
                {
                    rollback.Push(step.Rollback);
                    step.Do();
                }
            }
            catch (Exception ex)
            {
                //handle exception...

                //roll back all changes
                while (rollback.Count > 0)
                {
                    rollback.Pop()();
                }
            }
        }
    }

    public class Step1 : IStep
    {
        public void Do()
        {
            Console.WriteLine("Do step1 ...");
        }

        public void Rollback()
        {
            Console.WriteLine("Roll back step1 ...");
        }

    }
    public class Step2 : IStep
    {
        public void Do()
        {
            Console.WriteLine("Do step2 ...");
        }

        public void Rollback()
        {
            Console.WriteLine("Roll back step2 ...");
        }

    }
    public class Step3 : IStep
    {
        public void Do()
        {
            Console.WriteLine("Do step3 ...");
            throw new Exception("test exception...");
        }

        public void Rollback()
        {
            Console.WriteLine("Roll back step3 ...");
        }

    }

测试运行-

    StepHelper.RunSteps(new List<IStep>()
    {
        new Step1(),
        new Step2(),
        new Step3()
    });