处理自定义交易失败

问题描述 投票:0回答:1

我有一个用例,在我的服务中将创建实体操作标记为成功,我必须将一些元数据写入DataBase 1(我的服务可以直接访问数据库),在内部调用我当前服务的另一个API,该API将保留一些数据库 2(我的服务可以直接访问的 graphdb)中的关系,然后将数据库 3 中的实体状态标记为“活动”,从而将创建实体操作标记为成功。这3个数据库都是NoSQL数据库。我正在寻找处理部分失败的策略和回滚策略。我的客户可以同步和异步调用创建实体操作 api。我处理部分失败的思维过程是在所有重试都用尽之后,将原始创建实体操作请求移至 DLQ,对该 DLQ 中的消息数量发出警报,以便可以通知 oncall 并查看请求以进行调试。如果根本原因表明底层系统存在暂时性问题,则 oncall 可以将原始请求重新驱动到源队列,以便重试该请求,以便从部分故障中恢复,否则可以进一步调试并进行系统更正和回填从部分失败中恢复

对于异步流程,这对我来说似乎很好,但对于同步调用,我知道我们应该向客户端抛出异常,并让他们决定是否重试请求,但我想了解如何处理部分失败数据保存在数据库中:

  • 我应该在向客户端抛出异常之前即时实现自定义回滚场景吗?在这种情况下,人们如何实现自定义回滚?任何参考都会有很大帮助吗?

  • 或者我应该有一个离线系统/计划作业来执行由于数据库部分故障而进行的数据例行清理(例如每 24 小时一次)吗?

rollback distributed-transactions
1个回答
0
投票

使用SAGA模式。通过像temporal.io这样的编排器来实现它。它适用于两种同步用例。您始终可以向客户端返回异常,然后异步执行补偿。

这是 Booking SAGA sample 中的片段:

public void bookVacation(BookingInfo info) {
        Saga saga = new Saga();
        try {
            saga.addCompensation(activities::cancelHotel,
                                 info.getClientId());
            activities.bookHotel(info);

            saga.addCompensation(activities::cancelFlight, info.getClientId());
            activities.bookFlight(info);

            saga.addCompensation(activities::cancelExcursion, info.getClientId());
            activities.bookExcursion(info);
        } catch (TemporalFailure e) {
            saga.compensate();
            throw e;
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.