首页 > 解决方案 > 变异隐式“上下文”参数

问题描述

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

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

一切都很好,直到这个上下文是只读的。现在我需要实现域事件方法并仅在事务提交后调度事件。所以我决定将事件列表存储在上下文中,并在成功转换DBIOFuture.

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

标签: scalaakkaslickakka-httpscala-cats

解决方案


如果您考虑使用 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 就像一些数据的原子包装器,并使用您定义的效果来提供一些安全性。

还有其他选择:

  • 忽略引用透明度,只传递可变数据结构
  • 使用像 StateT 或 WriterT 这样的 monad 转换器

你选择什么是一个偏好问题。


推荐阅读