2017-06-07 5 views
2

Nach dem Erhalt einer Future[httpResponse] Ich versuche, die Nachricht an die sender senden, aber ich bin der Verweis auf die sender verlieren. HierAkka http verlieren Sender Referenz

ist der Code meiner empfangen Methode:

def receive = { 
     case Seq(method: HttpMethod, endpoint: String, payload: String) ⇒ { 
      // I have the correct sender reference 
      implicit val materializer: ActorMaterializer = ActorMaterializer(ActorMaterializerSettings(context.system)) // needed by singleRequest method below 
      // I have the correct sender reference 

      val response: Future[HttpResponse] = Http(context.system).singleRequest(HttpRequest(method = method, uri = endpoint, entity = payload)) 
      println("http request sent") 
      // I have the correct sender reference 
      response onSuccess { 
      case HttpResponse(statusCode, _, entity, _) ⇒ { 
       entity.dataBytes.runFold(ByteString.empty)(_ ++ _).foreach { body ⇒ 
       // NO Reference to sender 
       sender ! HttpConsumerResponse(statusCode = statusCode, contentType = entity.contentType, body = body.utf8String) 
       } 
      } 
      case _ => println("http request success 2") 
      } 

      response onFailure { 
      case exception: Throwable ⇒ { 
       println("http request failure") 
       throw exception 
      } // Adopting let-it-crash fashion by re-throwning the exception 
      } 
     } 
     case _ => println("I am httpConsumerActor and I don't know") 
     } 

Wenn ich den Code wie folgt zu ändern:

def receive = { 
     case Seq(method: HttpMethod, endpoint: String, payload: String) ⇒ { 
      // I have the correct sender reference 
      implicit val materializer: ActorMaterializer = ActorMaterializer(ActorMaterializerSettings(context.system)) // needed by singleRequest method below 
      // I have the correct sender reference 

      val response: Future[HttpResponse] = Http(context.system).singleRequest(HttpRequest(method = method, uri = endpoint, entity = payload)) 
      println("http request sent") 
      // I have the correct sender reference 
      val mySender = sender 
      response onSuccess { 
      case HttpResponse(statusCode, _, entity, _) ⇒ { 
       entity.dataBytes.runFold(ByteString.empty)(_ ++ _).foreach { body ⇒ 
       // NO Reference to sender 
       mySender ! HttpConsumerResponse(statusCode = statusCode, contentType = entity.contentType, body = body.utf8String) 
       } 
      } 
      case _ => println("http request success 2") 
      } 

      response onFailure { 
      case exception: Throwable ⇒ { 
       println("http request failure") 
       throw exception 
      } // Adopting let-it-crash fashion by re-throwning the exception 
      } 
     } 
     case _ => println("I am httpConsumerActor and I don't know") 
     } 

alles funktioniert, aber ich habe den Bezug des Darstellers senden wie mit Diese Zeile und ich weiß, das ist nicht der beste Weg, dies zu tun:

val mySender = sender 

Antwort

6

Der Grund, warum Ihre erste Annäherung doe s nicht arbeiten ist, dass Sie "umschaltbaren Zustand" schließen, d. h. die sender() Methode wird ausgeführt, wenn die onComplete ausgeführt wird, und enthält die Referenz nicht mehr. Das ist ein ziemlich verbreiteter Fehler in Akka, wir waren alle dort! :)

Die richtige Lösung, wie Sie bereits selbst herausgefunden haben, ist es, die Referenz vorab zu speichern. Es gibt andere Möglichkeiten, wie "etwas" zu werden, aber für Ihre Verwendung würde ich sagen, dass der Pre-Store der richtige Ansatz in Bezug auf den Kompromiss zwischen "nett" und "einfach" ist. siehe

als Referenz auf diese Ressourcen: SO question, Blog post

+1

Weitere Referenz, die Akka docs: http://doc.akka.io/docs/akka/current/scala/additional/faq.html#sender-getsender -disappears-when-i-use-Zukunft-in-meinem-Schauspieler-warum- – johanandren