Passing request context implicitly in the actor system

I would like to distribute the request context implicitly in the system of collaborating entities.

To simplify and present the situation, my system has several participants, and messages sent to these entities should include this RequestContext object.

ActorA receives messages of type MessageA ActorB receives messages of type MessageB

when ActorA needs to send a message to ActorB as part of MessageA processing, it executes the business logic and then creates a MessageB from the results of the logic as well as RequestContext available in MessageA and then sends them to ActorB

def handle(ma:MessageA) {
 val intermediateResult = businessLogic(ma)
 actorB ! MessageB(intermediateResult, ma.requestContext)
}

We have a lot of messages that need to be processed, and explicitly walking around requestContext is cumbersome.

I am trying to use creative ways to use the Scala implicits function to avoid explicitly embedding the RequestContext object embedded in the incoming message into the outgoing message.

Messages are case classes (and they should be). I read about implicits rules, but casting an attribute of an object to the current implicit scope seems far-fetched.

This, I am sure, should be a general requirement. Any suggestions?

Thank.

+5
source share
3 answers

In my opinion, the easiest way is to make your val implicit in the case class.

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)
}
+6
source

In your example, your processing of the message in question is forced into an existing method that makes it straightforward:

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)
  }
}

, , 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)
}
+6

, , . , Actor ( akka._). aroundReceive(), , , , , , . , , Actor.sender().

, , ActorRef, tell/ask -.

, , . , , - , , ThreadLocal, Future-based .., sync/async .

0

All Articles