临时保存发件人(ActorRef)以便稍后回复

时间:2013-12-31 12:57:44

标签: scala akka actor

临时保存发件人以便稍后回复

我有3个演员

class Actor1 extends Actor {
  val actor2 = context actorOf (Props[Actor2])
  actor2 ! Actor2Request

  def receive = {
    case data: String => // need to receive it
  }
}

class Actor2 extends Actor {

  def receive = {
    case Actor2Request =>
      //sender is Actor1 but I want to save it now and reply it later on in "case DoneActor3(data: String)"
      val actor3 = context actorOf (Props[Actor3])
      actor3 ! Actor3Request

    case DoneActor3(data: String) =>
      // doing something with data
      // and then send it to Actor1
      sender ! data //ops! sender is Actor3 now, not Actor1!
  }
}

class Actor3 extends Actor {

  def receive = {
    case Actor3Request =>
      //doing some work...
      sender ! DoneActor3(data) // sender is Actor2 and that's ok! 
  }
}

查看Actor2代码,我希望在收到sender消息时保存Actor2Request Actor1 )并回复此sender } Actor2收到DoneActor3(data: String)消息后。

有没有惯用的方法呢?

2 个答案:

答案 0 :(得分:2)

使用forward,在演员之间传递消息时保留原始发件人。 在这种情况下,您甚至不需要通过Actor2

发送返回数据
class Actor2 extends Actor {
  def receive = {
    case Actor2Request =>
      val actor3 = context actorOf (Props[Actor3])
      //sender will still be actor1 when actor3 receives this forwarded message
      actor3 forward Actor3Request
  }
}

class Actor3 extends Actor {
  def receive = {
    case Actor3Request =>
      //doing some work...
      sender ! data // sender is actor1
  }
}

如果你需要通过Actor2返回,也许是为了进行一些中间处理,那么你想捕获原始发件人并通过actor消息传递它:

class Actor2 extends Actor {
  def receive = {
    case Actor2Request =>
      val actor3 = context actorOf (Props[Actor3])
      //sender at this point is actor1
      actor3 ! Actor3Request(sender)

    case DoneActor3(origin, data) =>
      // Do some other stuff here
      origin ! data //origin is the original sender as passed to Actor3Request
  }
}

class Actor3 extends Actor {
  def receive = {
    case Actor3Request(origin) =>
      //doing some work...
      sender ! DoneActor3(origin, data) // origin is actor1, sender is actor2
  }
}

或者你可以混合使用匹配这些技巧,让Actor3直接向origin

发送消息

<强>更新

有一个最终解决方案,此处有效,因为actor2actor1创建。在这种情况下,我们知道actor1将成为监督层次结构中actor2的父级:

class Actor2 extends Actor {
  def receive = {
    case Actor2Request =>
      val actor3 = context actorOf (Props[Actor3])
      actor3 ! Actor3Request

    case DoneActor3(data) =>
      // Do some other stuff here
      context.parent ! data //context.parent is actor1
  }
}

class Actor3 extends Actor {
  def receive = {
    case Actor3Request =>
      //doing some work...
      sender ! DoneActor3(data) //sender is actor2
  }
}

答案 1 :(得分:0)

只需将ActorRef保存在var中,稍后再使用:

class Actor2 extends Actor {

  private var requester: ActorRef = _

  def receive = {
    case Actor2Request =>
      requester = sender
      val actor3 = context actorOf (Props[Actor3])
      actor3 ! Actor3Request

    case DoneActor3(data: String) =>
      requester ! data 
  }
}

这就是演员的目的,跟踪不断变化的状态。我知道Scala不鼓励使用var,但在演员的背景下它完全没问题。

修改评论:您的Actor2是在Actor1中创建的,它们之间存在一对一的关联,因此,即使您有多个Actor1个实例,每个人都有自己的孩子Actor2。我不知道您对此设计的目标是什么,另一种方法是用户parent而不是sender中的Actor2,这将指向创建的Actor1它,或者你可以传递ActorRef的{​​{1}}作为Actor1的构造函数的参数。