补偿交易模式 Compensating Transaction Pattern

未匹配的标注

描述

    在最终一致性模型中,典型的业务操作由一系列自治步骤组成。如果一个或多个步骤失败,失败步骤的回滚操作将会由一系列执行的工作的步骤组成,这些步骤一起定义最终一致。

背景和问题

    在执行这些步骤时,系统状态的总体视图可能是不一致的,但是当操作完成并且所有步骤都已经执行时,系统应该再次变得一致。在最终一致性模型中,某些步骤是无法恢复的。例如转账业务。

解决方案

    实现补偿事务。补偿事务必须撤消原始操作步骤的效果。补偿事务中步骤的顺序不一定是原来步骤的相反,也可以是其他抵消效果的操作。

注意事项

  1. 完整的操作日志。必须能够监视补偿逻辑的生命周期。
  2. 将补偿事务中的步骤定义为幂等命令。因为如果补偿事务失败,还可以重复这些步骤。
  3. 超时机制。所有操作必须在锁过期前完成。
  4. 重试机制。如果补偿失败,可以重新触发。

何时使用

符合所有步骤都可以回滚或能达到撤销效果的补偿事务。

可用到的设计模式思维

    每个步骤都有自己独立的逻辑,每个步骤都可以看成一个指令。这里可以使用命令模式处理。

结构中包含的角色

  1. StepCommand 抽象步骤命令
  2. ConcreteStepCommand 具体步骤命令
  3. Transactor 交易者

最小可表达代码

interface StepCommand
{
    public function handle() : bool;
}

class OneStepCommand implements StepCommand
{
    public function handle() : bool
    {
        var_dump('记录步骤1 - 操作成功');
        return true;
    }
}

class TwoStepCommand implements StepCommand
{
    public function handle() : bool
    {
        var_dump('记录步骤2 - 操作失败');
        return false;
    }
}

class OneRollBackStepCommand implements StepCommand
{
    public function handle() : bool
    {
        var_dump('记录回滚步骤1 - 操作成功');
        return true;
    }
}

class TwoRollBackStepCommand implements StepCommand
{
    public function handle() : bool
    {
        var_dump('记录回滚步骤2 - 操作成功');
        return true;
    }
}

// 交易者
class Transactor
{
    private $currentIndex = 0;
    private $commands = [];
    private $rollBackStepCommands = [];

    public function addCommand(StepCommand $stepCommand, StepCommand $rollBackStepCommand)
    {
        $this->commands[] = $stepCommand;
        $this->rollBackStepCommands[] = $rollBackStepCommand;
    }

    public function execute()
    {
        $status = true;
        // 正常流程执行步骤
        foreach ($this->commands as $index => $command) {
            $this->currentIndex = $index;

            if (! $status = $command->handle()) {
                break;
            }
        }

        if ($status) {
            return;
        }

        // 回滚步骤
        foreach ($this->rollBackStepCommands as $index => $rollBackStepCommand) {
            if (! $status = $rollBackStepCommand->handle()) {
                throw new \Exception("交易异常,启动异常机制");
            }

            if ($this->currentIndex = $index) {
                break;
            }
        }   
    }
}

$transactor = new Transactor();
$transactor->addCommand(new OneStepCommand, new OneRollBackStepCommand);
$transactor->addCommand(new TwoStepCommand, new TwoRollBackStepCommand);
$transactor->execute();

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
发起讨论 只看当前版本


暂无话题~