2016-08-10 3 views
0

Ich bin langsam um Futures in Scala, und habe ein bisschen eine Schicht Kuchen, die ich versuche zu enträtseln. Der spezifische Anwendungsfall ist ein DeferredResolver in sangria-graphql + akka. Ich habe ihren Demo-Code gestohlen, der so aussiehtIn Scala Futures verloren

Future.fromTry(Try(
    friendIds map (id => CharacterRepo.humans.find(_.id == id) orElse CharacterRepo.droids.find(_.id == id)))) 

und fügte meine eigene Modifikation hinzu. Ihrige tut eine Lookup im Speicher, während mein etwas von einem anderen Schauspieler fragt:

Future.fromTry(Try(
    accountIds match { 
     case h :: _ => 
     val f = sender ? TargetedMessage(h) 
     val resp = Await.result(f, timeout.duration).asInstanceOf[TargetedMessage] 
     marshallAccount(resp.body) 

     case _ => throw new Exception("Not found") 
    } 
)) 

Die zugehörige Stück hier ist, dass ich das erste Element in der Liste auswählen, senden Sie es an einem ActorRef, die ich an anderer Stelle bekam und warten das Ergebnis. Das funktioniert. Was ich aber tun möchten, müssen nicht hier, auf das Ergebnis warten, aber die ganze Sache als Future

Future.fromTry(Try(
    accountIds match { 
     case h :: _ => 
     sender ? TargetedMessage(h) map { 
      case resp:TargetedMessage => marshallAccount(resp.body) 
     } 

     case _ => throw new Exception("Not found") 
    } 
)) 

Das funktioniert nicht zurück. Wenn diese verbraucht wird, statt Account vom Typ sein (der Rückgabetyp der Funktion marshallAccount, es vom Typ Promise. Wenn ich richtig verstehe, dann ist es, weil stattdessen einen Rückgabetyp Future[Account] zu haben, hat dies eine Art von Future[Future[Account]]

Wie abflachen ich diese

Antwort

3

Sie sind an der falschen API-Methode suchen Future.fromTry verwendet wird, um eine sofort gelöst Zukunft zu schaffen, das heißt der Anruf nicht tatsächlich asynchron ist Tauchen Sie ein in die Umsetzung von Future.fromTry, die Sie brauchen:?..

def fromTry[T](result: Try[T]): Promise[T] = new impl.Promise.KeptPromise[T](result) 

Ein Versprechen gehalten ist im Grunde etwas, das bereits passiert ist, so wie Future.successful wird dies nur verwendet, um den richtigen Rückgabetyp oder ähnliches zu gewährleisten, es ist nicht wirklich eine Möglichkeit, etwas Asynchrones zu machen.

Der Grund, warum der Rückgabetyp Future[Future[Something]]10 ist, weil Sie versuchen, etwas zu verpacken, das bereits eine Zukunft in eine andere Zukunft zurückgibt.

Das ask-Muster, nämlich sender ? TargetMessage(h) ist ein Weg zu fragen Sie etwas von einem Schauspieler und warten auf ein Ergebnis, das eine Zukunft zurückgeben wird.

Der richtige Weg, dies zu nähern:

val future: Future[Account] = accountIds match { 
    case h :: _ => sender ? TargetedMessage(h) map (marshallAccount(_.body) 
    case _ => Future.failed(throw new Exception("Not found")) 
} 

Grundsätzlich müssen Sie Future.failed verwenden eine ausgefallene Zukunft von einer Ausnahme zurück, wenn Sie den Rückgabetyp konsistent halten wollen. Es lohnt sich, this tutorial zu lesen, um etwas mehr über Futures zu lernen und Anwendungslogik mit ihnen zu schreiben.