在actor系统中隐式传递请求上下文

vis*_*shr 5 scala implicit implicit-conversion actor akka

我想在协作actor的系统中隐式地传播请求上下文.

为了简化和呈现这种情况,我的系统有多个actor,传递给这些actor的消息需要包含这个RequestContext对象.

ActorA接收MessageA类型的消息,ActorB接收MessageB类型的消息

当ActorA需要向ActorB发送消息时,作为MessageA处理的一部分,它执行业务逻辑,然后根据逻辑结果以及MessageA中可用的RequestContext构造MessageB,然后将其发送给ActorB

def handle(ma:MessageA) {
 val intermediateResult = businessLogic(ma)
 actorB ! MessageB(intermediateResult, ma.requestContext)
}
Run Code Online (Sandbox Code Playgroud)

我们有一大堆要处理的消息,并且明确地传递requestContext是很麻烦的.

我正在尝试使用Scala的implicits功能创建方法,以避免将传入消息中嵌入的RequestContext显式注入传出消息.

消息是案例类(它们需要).我已经阅读了有关implicits规则的内容,但是将对象的属性带入当前的隐式范围似乎很牵强.

我相信这应该是一个共同的要求.有什么建议 ?

谢谢.

Rol*_*uhn 6

在您的示例中,您对有问题的消息的处理已经被分解为一个方法,这使得这个直截了当:

trait RequestContext

case class MessageA(req: RequestA, ctx: RequestContext)
object MessageA {
  def apply(req: RequestA)(implicit ctx: RequestContext) = MessageA(req, ctx)
}

case class MessageB(req: RequestB, ctx: RequestContext)
object MessageB {
  def apply(req: RequestB)(implicit ctx: RequestContext) = MessageB(req, ctx)
}

class Example extends Actor {

  def receive = {
    case MessageA(req, ctx) => handle(req)(ctx)
  }

  def handle(req: RequestA)(implicit ctx: RequestContext): Unit = {
    val intermediateResult = businessLogic(req) // could take implicit ctx as well
    actorB ! MessageB(intermediateResult)
  }
}
Run Code Online (Sandbox Code Playgroud)

但正如您所看到的,在声明消息类型时仍然存在一些开销,并且handle方法的签名也需要更改.这种方案是否值得,取决于这些隐含价值的消费者和生产者之间的比例(即,如果handle使用上下文不止一件事,那就更有意义).

上述的变体可以是:

case class MessageA(req: RequestA, ctx: RequestContext)
object MessageA {
  def apply(req: RequestA)(implicit ctx: RequestContext) = MessageA(req, ctx)
  implicit def toContext(implicit msg: MessageA) = msg.ctx
}

case class MessageB(req: RequestB, ctx: RequestContext)
object MessageB {
  def apply(req: RequestB)(implicit ctx: RequestContext) = MessageB(req, ctx)
  implicit def toContext(implicit msg: MessageB) = msg.ctx
}

...
def handle(implicit ma: MessageA): Unit = {
  val intermediateResult = businessLogic(req)
  actorB ! MessageB(intermediateResult)
}
Run Code Online (Sandbox Code Playgroud)


Edm*_*984 6

在我看来,最简单的方法是使你的val隐含在case类中.

case class MessageA(req: RequestA)(implicit val ctx: RequestContext)

case class MessageB(req: RequestB)(implicit val ctx: RequestContext)

def businessLogic(req:RequestA):RequestB


def handle(ma: MessageA): Unit = {
  // import all the members of ma so that there is a legal implicit RequestContext in scope
  import ma._
  val intermediateResult = businessLogic(req)
  actorB ! MessageB(intermediateResult)
}
Run Code Online (Sandbox Code Playgroud)