我正在开发一个单页Web应用程序,它将使用NoSQL文档数据库(如MongoDB),我想在我对我的实体进行更改时生成事件。
由于大多数这些数据库仅支持文档级别的事务(MongoDB刚刚添加了ASIC支持),因此没有好的方法可以将更改存储在一个文档中,然后将这些更改中的事件存储到其他文档中。
比方说,我有一个集合'Events'和一个像Trello那样的'Cards'集合。当我从'Cards'集合中更改卡片的描述时,应该生成一个事件'CardDescriptionChanged'。
问题是,如果将更改保存到'Cards'集合并在'Events'集合中添加事件之间发生崩溃或出现错误,则此事件将不会保留,我不希望这样。
我已就此问题做过一些研究,大多数人会建议可以使用以下几种方法之一:
我考虑过选项4,但有几个问题出现了:
我可以为同一个实体(如卡或板)排队所有命令,并确保它们按顺序处理,而不同实体(不同卡)的事件可以并行处理。然后我可以使用已处理的命令作为事件。这里的一个问题是对实体的改变可能生成可能不对应于单个命令的若干事件。我将不得不细分所有用户操作的细粒度命令,以便我可以将它们转换为事件。
如果此过程是异步的,我必须管理到客户端的错误报告。而且我还必须删除或标记失败的命令。
由于Trello使用MongoDB并生成动作('DeleteCardAction','CreateCardAction')并更改实体(卡片,板......),我想知道他们是如何解决这个问题的?
创建一个名为FutureUpdates
的新集合。使用单个文档将计划更新写入FutureUpdates
集合,该文档定义您计划对卡片所做的更改以及您计划生成的事件。这个插入是原子的。
现在拿一张[ChangeStream][1]
的FutureUpdates
系列,这将为您提供所需的更新流。从更改流中获取每个文档并应用更新。最后,更新FutureUpdates
中的doc以将其标记为完成。此更新将再次是原子的。
将更新应用于事件和卡时,请确保包含用于在FutureUpdates
中创建更新的文档的objectID。
现在,如果在FutureUpdates
中插入更新后程序崩溃,您可以检查事件和卡集合是否存在包含更新的objectID的记录。如果它们不存在,那么您可以重新应用缺少的更新。
如果已应用更新但FutureUpdate
doc未标记为完成,我们可以在恢复期间更新该更新以完成此过程。
实际上,您可以不断以原子方式更新FutureUpdates
中每个更改的文档以跟踪进度。更新完成后,您可以归档旧文档或只删除它们。