在 Datomic 中需要泛化比较和交换语义的情况下如何设计?
Posted
技术标签:
【中文标题】在 Datomic 中需要泛化比较和交换语义的情况下如何设计?【英文标题】:How to design at the situation that we need generalized compare-and-swap semantic in Datomic? 【发布时间】:2019-04-16 10:51:26 【问题描述】:我的问题是这样的:
我需要使用 Datomic 来建模:
-
用户可以提出请求。最初,请求处于打开状态。
管理员可以批准/拒绝/修改用户请求。
请求架构如下:
:req/status ;; cardinality one. It can be: open, modified, approved, rejected
:req/things ;; cardinality many. [thing-id ...]
管理员可以看到来自 Web 应用程序 UI 的用户请求。管理员有三个选项:批准、拒绝、修改。如果请求被批准或拒绝,则该请求不再有效。它将从管理 UI 中消失。但是,如果请求被修改,它仍然可以被批准、被拒绝或再次修改。修改请求时,只能修改req/things
。在这个系统中,可能有多个管理员同时对同一个请求进行操作。
请求状态的状态图为:
open -> modified
modified -> modified
modified, open -> approved (done)
modified, open -> rejected (done)
考虑一种情况:
两个管理员 A 和 B 处理同一个请求,但他们没有感知到对方。他们同时按下按钮。一位管理员 A 批准该请求,另一位管理员 B 修改该请求。该请求最初是在之前修改过的,所以在两个管理员处理它时它的状态为modified
。
系统的正确行为可能有两种可能:管理员 A 操作成功或管理员 B 操作成功。如果admin A先操作成功,则不能再修改请求。如果admin B先操作成功,那么A的审批应该不会发生,因为req/things
已经被修改了,但是admin A审批了另外一组req/things
。
我考虑使用db.fn/cas
来保证admin A 或admin B 只有一次操作可以成功。但是,db.fn/cas
不适用于许多基数。
目前,我认为有两种方法可以解决我的问题(只有一个操作可以成功):
添加一个额外的架构req/stamp
到 req.
戳记初始为0,每次操作都会增加1。然后我可以使用这个戳记和db.fn/cas
来保证操作的逻辑严格性。
安装一些自定义的db函数,如this,可以对基数做CAS,保证逻辑上的严格性。
我很好奇在 Datomic 中哪种方式更规范地解决这个问题,或者还有另一种方式来解决这种问题?
【问题讨论】:
我发现 Mongoose 从版本 3 开始有一个类似的设计,叫做versionKey
,对应我原来问题中的req/stamp
。
【参考方案1】:
绝对不是专家,但我认为在此用例中引入时间戳并在事务中进行比较更简单。
【讨论】:
以上是关于在 Datomic 中需要泛化比较和交换语义的情况下如何设计?的主要内容,如果未能解决你的问题,请参考以下文章