繁体   English   中英

如何在 akka 演员中使用未来价值

[英]how to use future value inside an akka actor

我想在父子层次结构中使用 akka 演员,父母可以将最终计算结果发送到可能/可能不是演员的调用代码这是我的用例

父->子->childManager

childManager 有三个工人演员(3 个孩子) childManager (worker1,worker2,worker3)

现在worker1获取值处理它并将其响应值发送给worker2

  • worker1->处理值并将结果发送给worker2
  • worker2->处理worker1结果并将worker2结果发送给worker3
  • worker3->处理worker2结果并将最终计算值发送给childManager
  • childManager 将结果发送给孩子
  • 孩子将结果发送给父母

这就是我想要做的

final case class GetValue(value:String)
final case class sendToChildManager(value:String)
final case class sendToChild(value:String)

final case class processToken(value:String)
final case class processPublicKey(value:String)
final case class processUserDeatils(accessToken:string,publicKey:PublicKey)

 class worker1 extends Actor {
  def receive {
    case ProcessToken(token)=>
    val request = httpRequest(token)
    request.onComplete{
      case Success(accessToken)=>
        //generate access token 
        sender ! accessToken
      case Failure(e)=>throw e
   }
  }
}

class worker2 extends Actor {
  def receive {
    case processPublicKey(token)=>
    val request=HttpRequest(token)//based on accessToken compute publicKey 
    request.onComplete {
      case Suceess(publicKey)=>
        // calculate publicKey from accessToken 
        sender ! publicKey
      case Failure(e)=>throw e
    }
  }
}

class worker3 extends Actor {

  def receive {
    case processUserDeatils(accessToken,publicKey)=>
    val request = HttpRequest(accessToken,publicKey)
    request.onCompelete {
      case Success(value)=>
        //process the resulted value got userInfo as a result 
        sender ! UserInfo
      case Failure(e)=> throw e
    }
  }
}

class ChildManager extends Actor {

  def receive {
    case sendtoChildManager(value)=>
    val worker1=context.actorOf//
    val worker2=context.actorOf//
    val worker3=context.actorOf//

    val futureToken = ask(worker1,processToken)
    futureToken.onComplete {
      case Sucess(token)=>
        val futurePublickKey = ask(worker2,processPublicKey(token))
        futurePublickKey.onComplete {
          case Sucess(publicKey)=>
            val futureVerified=ask(worker3,processUserDeatils(token,publicKey))
            futureVerified.pipeTo(sender)
          case Failure(e)=> throw e
        }
      case Failure(e)=>throw e
    }
  }
}

 class child extends Actor {
  val childMnager = context.actorOf//
  def receive {
    case sendToChild(value)=>
    childMnager.forward(sendtoChildManager(value))
  }

  class parent extends Actor {
    val child = context.actorOf()//

    def receive {
      case Getvalue(value)=>
      child.forward(sendtoChild(value))
    }
  }
}

object Main {
  def main {
    val system =ActorSystem("myActorsystem")
    val parent=system.actorOf(Props[Parent],"parent")
    val future=ask(parent,GetValue("token-id"))
    future.onComplete {
      case Success(result)=>Complete("user information is",result)
      case Failure(e) Complete("InternelserverError",e)
    }
  }
}

我已经读过,不建议在演员内部使用 onComplete ,它应该是发送者的 pipeTo

警告当使用未来的回调,如 onComplete,或 map,如 thenRun,或 thenApply 内部演员时,您需要小心避免关闭包含演员的引用,即不要在回调中调用方法或访问封闭演员上的可变 state。 这会破坏actor封装,并可能引入同步错误和竞争条件,因为回调将同时调度到封闭的actor。 不幸的是,目前还没有一种方法可以在编译时检测这些非法访问。 另请参阅:Actors 和共享可变 state 警告当使用未来的回调,例如 onComplete,或 map,例如 thenRun,或 thenApply 内部演员时,您需要小心避免关闭包含演员的引用,即不要调用方法或访问可变 state在回调中封闭演员。 这会破坏actor封装,并可能引入同步错误和竞争条件,因为回调将同时调度到封闭的actor。 不幸的是,目前还没有一种方法可以在编译时检测这些非法访问。 另请参阅:演员和共享可变 state https://doc.akka.io/docs/akka/current/actors.html#ask-send-receive-and-fu

但我想在一个演员内部进行所有处理,以便父演员将最终计算值返回给调用代码我该如何实现?
我正在使用 akka http

**Edit**

我的问题是我如何使用未来内部演员作为建议不要使用。map 或 onComplete 或等待,我不想将多个未来发送到调用代码然后计算最终结果我想发送最终计算调用代码的结果

如果您在 actor 内部使用异步 api,请不要使用 'sender' 属性。 只要您在接收 function 中编写同步代码,参与者就会提供互斥。 但是,当您创建未来时,您会创建一个可以在另一个线程中执行的新异步任务,同时消息仍在涌入参与者邮箱并且“发件人”属性发生变化。

你有两个选择:

  1. 使用 Akka 类型。 自从 Akka Typed 准备好投入生产以来,Akka 已经有了很大的改进。 我推荐这个选项。 使用 Akka 类型,您必须在消息的数据类型中包含引用。

  2. 为执行 Http 请求的每条消息创建一个匿名参与者,并保存原始发送者参与者引用。

您不能在Future中使用sender ,因为它是可变的 Actor state。 sender的值可以在每次调用receive方法时发生变化,并且在Future完成时可能会有所不同。

解决方案是捕获sender的值并在Future中使用捕获的值:

def receive = {
  case ProcessToken(token)=>
    val replyTo = sender // Capture current value of sender
    val request = httpRequest(token)

    request.onComplete{
      case Success(accessToken)=>
        //generate access token 
        replyTo ! accessToken
      case Failure(e) =>
        throw e
  }
}

类型化的 actor 不支持sender ,因此ProcessToken消息本身需要有一个replyTo字段。 此消息不是参与者 state 并且可以在Future中安全地访问。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM