2017-03-10 2 views
0

J'essaie d'obtenir la valeur d'un extrait de code qui résulte en Future, mais quand je cours le code, il s'avère qu'il n'entrera jamais la fonction onComplete. Y a-t-il quelque chose que je fasse mal?Scala Future ne pas entrer onComplete()

J'ai essayé d'utiliser une carte aussi bien depuis qu'il a été suggéré dans d'autres postes, mais ne l'ai pas eu du succès

override def findOrCreate(phoneNumber: String, creationReason: String): Future[AvroCustomer] = { 

     //query for customer in db 
     val avroCustomer: Future[AvroCustomer] = customerByPhone(phoneNumber) 

     avroCustomer.onComplete({ 
     case Success(null) => { 
      createUserAndEvent(phoneNumber, creationReason, 1.0) 
     } 

     case Success(customer) => { 
      Future.successful(customer) 
     } 

     case Failure(exception) => { 

     } 
}) 
+0

Est-ce que vous attendez le 'Future' à finir de courir dans le code qui appelle cela? Est-ce que vous obtenez peut-être un 'Failure' et l'ignorez? – jkinkead

+1

Peut-être votre avenir ne se termine-t-il pas vraiment très longtemps. Vous pouvez essayer 'Await.result' pour le débogage. – francoisr

+1

Futures sont _ventuellement_ là -> vous devez les attendre à un moment donné que @jkinkead a souligné. Si vous lancez un 'Future' à la fin du programme et que vous ne l'attendez pas, vous ne verrez jamais les résultats. – sebszyller

Répondre

2

Réponse à développer le commentaire. Ce programme factice n'imprimera rien.

import scala.concurrent.Future 
import scala.util.{Failure, Success} 
import scala.concurrent.ExecutionContext.Implicits.global 

object Quickie { 
    def main(args: Array[String]): Unit = { 
    val addOneInFuture: Future[Int] = Future(addOne(3)) 

    addOneInFuture.onComplete { 
     case Success(s) => println(s) 
     case Failure(ex) => println(ex.toString) 
     case _ => println("what the hell happened") 
    } 

    } 

    def addOne(x: Int): Int = x + 1 
} 

je lance un nouveau fil, mais puisque la valeur est jamais nécessaire que je ne verrai pas la version imprimée 4. Cependant, ajoutez un Await simple, Threed.sleep(_eternity_), diable même un autre println et vous verrez le résultat. Une chose à comprendre à propos de Futures dans Scala est que vous voulez composer et les traiter comme des collections (d'où il ya for-comprehensions pour eux) et vous avez rarement envie de faire quelque chose et d'imprimer. Si vous effectuez une opération de décompression ou de repos, vous allez traiter les données de toute façon.

Il y a une vieille série de blogs d'or de Daniel Westheide que vous pouviez lire. http://danielwestheide.com/blog/2013/01/09/the-neophytes-guide-to-scala-part-8-welcome-to-the-future.html

1

Imo, au lieu d'utiliser un OnComplete, qui ne reviendra pas ce que vous voulez (OnComplete est une méthode de type Unit), d'abord, vous pouvez attraper l'exception du côté DB, soit avec un type d'essai ou un récupérer, puis avoir votre méthode retourner un Option[AvroCustomer].

Ceci est un cas d'utilisation parfait pour les types de wrapper optionnels scala (la manière Scala-tastic de travailler avec des types null). Si customerByPhone renvoie null pour une raison quelconque, vous pouvez l'attraper du côté de la fonction db et le transformer en un type facultatif.

-à-dire, très rapidement, si c'est un type Nullable:

def customerByPhone(s: String) = { 
    ... //Some code 
    db.run(query).map(Option(_)) 
} 

Ce produit maintenant une Option[avroCustomer] que vous pouvez ensuite enchaîner ainsi:

override def findOrCreate(phoneNumber: String, creationReason: String): Future[AvroCustomer] = { 

     //query for customer in db 
     customerByPhone(phoneNumber).flatMap { 
     case Some(customer) => Future.successful(customer) 

     case None => createUserAndEvent(phoneNumber, creationReason, 1.0) //I'm assuming this returns a futures. 
     } 
}