2014-11-22 80 views
1

我正在开发旅行行程预订引擎。用例是这样的:什么是用异步事件实现状态引擎的正确方法?

  1. 客户预订一个涉及多个腿(一条腿是旅程的连续部分,由同一家公司工作)的旅程。例如。从亚特兰大到新德里的旅行可能由两条腿组成,亚特兰大 - 纽约和纽约 - 新德里。

  2. 每条腿都有自己的保留,可以处于“挂起”或“确认”状态(这实际上只是真实状态的捷径)。

  3. 一旦预订合作伙伴(例如,航空公司)确认预订,每个支票预订只允许从“挂起”转换到“确认”。这些是可能需要数秒至数天的异步事件。

  4. 所有支票预订都捆绑在代表客户预订状态的父预订中。只有在a)所有相关支线均“确认”后,才允许家长预订从“挂起”转换为“确认”,以及b)客户支付完成后。请注意,实际上“预订确认”和“付款确认”存在区别,但为简洁起见,我在此简化。

  5. 所有通信都是通过异步服务接口进行的,即可能需要几秒到几天的时间,直到收到支付预订或支付的确认。

请注意,行程预订子系统与支付子系统是分开的,即预订系统只能通过查询两个子系统来确定父预留状态。两个子系统都会收到异步事件,并且在发生某些事件时也会对预订系统执行回调。

另外请注意,该系统应该用于不同的客户,每个客户可以拥有自己的一组状态/转换(用于父级保留)。

问题:

  • 什么是管理中心,即父母预订的状态常用的方法,它依赖于外部子系统的状态?

  • 特别是,考虑到子系统确认的异步性,如何跟踪各个子状态?

  • 是否有组件开箱即可实现这样的分布式FSM(在Python生态系统中)?

我一直在思考以下方法:

  1. 实现一个“父预约FSM”反复尝试从“待定”到“确认”,每次查询相应的开关的状态付款和支付预留状态。在这种情况下,FSM主动尝试进入下一个状态(或在某个时刻超时)。这将作为一个周期性的芹菜任务来实现,它很简单地查询子系统,例如每30-60秒。

  2. 实现一个抽象的FSM(即工作流),该FSM在其状态发生变化时接收来自每个子系统的回调。在这种情况下,FSM跟踪收到的所有回调/事件,并且一旦收到所有腿事件的“付款正常”和“腿正常”,它就会将状态切换为“确认”。在这种情况下,FSM被动地等待事件到达。这将作为父保留对象来实现,该对象跟踪它收到的回调,然后设置父保留的状态。

第一种方法没有出现可扩展性,而第二种方法有不得不单独跟踪状态的缺点。我真正想要的是一个组件,它可以解决这个问题,而不必明确型号代码,允许为父预留FSM设置任意配置。

实现在Python中,使用Celery/RabbitMQ和Django。

+0

我不明白你对你提出的第二个解决方案的看法。你说它必须跟踪每个组件的状态,这是不利的。但是,如果每个组件都可以从挂起转换到确认,您是不是在跟踪它们? – 2014-11-22 21:23:06

+0

@加里凯恩斯,是的,每个组件都跟踪它们。我的意思是预订系统将复制每个组件的状态跟踪。所以预订系统基本上重新实现了子系统的FSM,这就是我的缺点。 – miraculixx 2014-11-22 22:12:10

回答

2

你的第二个选项的建议的细化:

  1. 创建的中间对象/数据库中的表称为像PendingBookings。其中的数据是主要预订的外键和未决腿数。我在这里假设,在初始预订时待处理腿的数量将不为零。
  2. 每当创建一条腿时,其保存方法也会增加PendingBookings对象中相应的未决腿数。
  3. 无论何时确认一条腿,其保存方法也会减少未决腿数。
  4. 当挂起的支腿数量达到0时,其保存方法将启动一个事务,将主要预订更新为已确认状态并删除PendingBookings实例。

这意味着您不必反复轮询物品,并且还可以为您提供一个位置,以查找有关已开始但尚未完成的所有预订的信息。然后,您可以不那么频繁地进行调查,可能每天一次进入一个OLAP多维数据集,以获取有关通过系统进行预订的信息。

我还会争辩说这里没有重复 - 您将有用的状态信息存储在一个地方,并在您不再需要时将其消除。

+0

谢谢你的回答,Garry。我不确定我喜欢倒计时,因为它不是幂等的。考虑到中间表将接收状态更新作为消息(即web服务调用或通过异步消息传递),系统将需要准确一次的语义和可靠的消息传递,这相对难以实现。 – miraculixx 2014-11-29 17:44:51

相关问题