在akka Actor系统之外发送响应

时间:2017-08-13 18:53:16

标签: scala akka akka-actor

我有一个游戏(2.4.2有akka 2.4.18)应用程序,我在其中使用akka actor来上传文件。我有一个具有这种层次结构的父级主管演员

  

UploadSupervisor --- child ---> UploadActor ---孩子--->
  DataWriteActor& MetaWriteActor

叶子演员MetaWriteActor& DataWriteActor进行实际编写。我的代码的一个非常简化的版本如下:

首先,我有一位演员主管:

class UploadSupervisor extends Actor {
  val uploadActor = context.actorOf(Props(new UploadActor), "UploadActor") 
 override def supervisorStrategy = OneForOneStrategy() {
    case _: Throwable => Restart
 }

override def receive: Receive = {
  case data: Data => uploadActor ! data
  case meta: MetaInfo => uploadActor ! meta
  //How do I send response outside of actor system?
  case dataSuccess: DataUploadResponse => ??? //Line 10
  case metaSuccess: MetaUploadResponse => ??? //Line 11

}

object UploadSupervisor {
  val uploadSupervisor = Akka.system
    .actorOf(Props(new UploadSupervisor), "UploadSupervisor")
}
//Request & Response case classes
case class Data(content: String)
case class MetaInfo(id: String, createdDate: Timestamp)

case class DataUploadResponse(location: String)
case class MetaUploadResponse(location: String)

UploadActor: -

class UploadActor extends Actor {  
val dataWriteActor = context.actorOf(Props(new DataWriteActor), "dataWriteActor")  
val metaWriteActor = context.actorOf(Props(new MetaWriteActor), "UploadActor")

override def receive = {   
case data: Data => dataWriteActor ! data   
case meta: MetaInfo => metaWriteActor ! meta   
case dataResp: DataUploadResponse => context.parent ! dataResp   
case metaResp: MetaUploadResponse => context.parent ! metaResp 

 }
}

DataWriteActor:

class DataWriteActor extends Actor {
  case data: Data => //Do the writing 
                     println("data write completed")
                     sender() ! DataUploadResponse("someLocation")  

}

MetaWriteActor

class MetaWriteActor extends Actor {
  case meta: MetaInfo=> //Do the writing 
                     println(" meta info writing completed")
                     sender() ! MetaUploadResponse("someOtherLocation")  

}

在Actor系统之外的某处: -

implicit val timeout = Timeout(10 seconds)
val f1 = UploadSupervisor.uploadSupervisor ? Data("Hello Akka").mapTo(implicitly[scala.reflect.ClassTag[DataUploadResponse]])

val f2 = UploadSupervisor.uploadSupervisor ? MetaInfo("1234", new Timestamp(new Date().getTime).mapTo(implicitly[scala.reflect.ClassTag[MetaUploadResponse]])

//Do something with futures

问题是如何在演员系统之外发送响应?因为在第10行& 11,我不能使用发件人! msg,因为当前发件人是UploadActor。

1 个答案:

答案 0 :(得分:1)

您可以保留UploadSupervisor对初始发件人的引用:

class UploadSupervisor extends Actor {
  val uploadActor = context.actorOf(Props[UploadActor], "UploadActor")

  override val supervisorStrategy = OneForOneStrategy() {
    case _ => Restart
  }

  var dataSender: Option[ActorRef] = None
  var metaSender: Option[ActorRef] = None

  def receive = {
    case data: Data =>
      val s = sender
      dataSender = Option(s)
      uploadActor ! data
    case meta: MetaInfo =>
      val s = sender
      metaSender = Option(s)
      uploadActor ! meta
    case dataSuccess: DataUploadResponse =>
      dataSender.foreach(_ ! dataSuccess)
    case metaSuccess: MetaUploadResponse =>
      metaSender.foreach(_ ! metaSuccess)
  }
}

UploadSupervisor发送消息:

implicit val timeout = Timeout(10 seconds)

val f1 = (UploadSupervisor.uploadSupervisor ? Data("Hello Akka")).mapTo[DataUploadResponse]

val f2 = (UploadSupervisor.uploadSupervisor ? MetaInfo("1234", new Timestamp(new Date().getTime)).mapTo[MetaUploadResponse]

以上假设您一次向Data发送一条MetaInfo条消息和一条UploadSupervisor条消息。如果您发送多个DataMetaInfo消息并期望并发回复,则此方法将会中断。更通用的解决方案是在包含现有案例类的其他案例类中包含对初始发送者的引用,并通过您的actor层次结构传递此引用:

case class DataMsg(data: Data, target: ActorRef)
case class MetaInfoMsg(metaInfo: MetaInfo, target: ActorRef)

case class DataUploadMsg(response: DataUploadResponse, target: ActorRef)
case class MetaUploadMsg(response: MetaUploadResponse, target: ActorRef)

class UploadSupervisor extends Actor {
  val uploadActor = context.actorOf(Props[UploadActor], "UploadActor")

  override val supervisorStrategy = OneForOneStrategy() {
    case _ => Restart
  }

  def receive = {
    case data: Data =>
      val s = sender
      uploadActor ! DataMsg(data, s)
    case meta: MetaInfo =>
      val s = sender
      uploadActor ! MetaInfoMsg(meta, s)
    case DataUploadMsg(response, target) =>
      target ! response
    case MetaUploadMsg(response, target) =>
      target ! response
  }
}

UploadActor

class UploadActor extends Actor {  
  val dataWriteActor = context.actorOf(Props[DataWriteActor], "dataWriteActor")  
  val metaWriteActor = context.actorOf(Props[MetaWriteActor], "UploadActor")

  def receive = {   
    case data: DataMsg => dataWriteActor ! data   
    case meta: MetaInfoMsg => metaWriteActor ! meta   
    case dataResp: DataUploadMsg => context.parent ! dataResp   
    case metaResp: MetaUploadMsg => context.parent ! metaResp 
  }
}

作家:

class DataWriteActor extends Actor {
  def receive = {
    case DataMsg(data, target) =>
      // do the writing 
      println("data write completed")
      sender ! DataUploadMsg(DataUploadResponse("someLocation"), target)
  }
}

class MetaWriteActor extends Actor {
  def receive = {
    case MetaInfoMsg(meta, target) =>
      // do the writing 
      println("meta info writing completed")
      sender ! MetaUploadMsg(MetaUploadResponse("someOtherLocation"), target) 
  }
}