改变隐式 "Context" 参数

Mutate implicit "Context" parameter

我有基于 akka-http 和 slick 构建的应用程序。所有服务都与灵活的 DBIO 实例一起工作,这些实例在路由 类 中转换为 Future。 通过服务广泛使用的隐式参数,用于传递有关当前请求的上下文(用户 ID、权限等)。典型方法签名如下所示:

def getProject(id: ProjectId)(implicit context: Context): DBIO[Project] = {???}

在此上下文为只读之前,一切都很好。 现在我需要实现 domain events 方法并仅在事务提交后分派事件。所以我决定在上下文中存储事件列表,并在成功将 DBIO 转换为 Future 后触发它们。

我的问题是如何以功能方式通过不同的服务方法正确地改变这个隐式上下文? 我考虑过使用 State monad transformer,但感觉它会带来更多复杂性,因为所有服务都已经构建在 DBIO.

之上

如果您考虑使用 Cats Effect,您可以使用 Ref 来存储事件。

val events: F[Ref[F, List[DomainEvent]]] = Ref.of[F, List[DomainEvent]](Nil)
// assuming that you'll make F=DBIO and provide necessary type class instances

def getProject(id: ProjectId)(implicit events: Ref[DBIO, List[DomainEvents]]): DBIO[Project] = for {
  ... // database actions
  _ <- events.update(list :+ event)
} yield ...

然后在 运行 交易之前:

for { 
  result <- ... // your queries, where you pass events 
  eventList <- events.get
} yield (result, eventList)

Ref 就像一些数据的原子包装器,并使用您定义的效果来提供一些安全性。

还有其他选项:

  • 忽略引用透明性,只传递可变数据结构
  • 使用一些 monad 转换器,如 StateT 或 WriterT

您选择什么是偏好问题。