Scala Future not entering onComplete()

2019-09-14 16:18发布

I am trying to grab the value from a snippet of code that results in a Future, but when I run through the code, it turns out that it never enters the onComplete function. Is there anything I'm doing wrong?

I've tried using a map as well since it was suggested in other posts, but haven't had success

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) => {

        }
})

2条回答
倾城 Initia
2楼-- · 2019-09-14 16:45

Imo, instead of using an OnComplete, which will not return what you want (OnComplete is a method of type Unit), first, you can try catching the exception on the DB side, either with a Try type or a recover, then have your method return an Option[AvroCustomer].

This is a perfect use case for scala Optional wrapper types (the Scala-tastic way of working with null types). If customerByPhone returns null for whatever reason, you could catch it on the db function side and turn it into an optional type.

i.e, very quickly, if it's a nullable type:

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

This now produces an Option[avroCustomer] which you can then chain this way:

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.
      }
}     
查看更多
神经病院院长
3楼-- · 2019-09-14 16:54

Answer to expand on the comment. This dummy program will not print anything.

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
}

I fire up a new thread but since the value is never needed I will not see the printed 4. However, add a simple Await, Threed.sleep(_eternity_), heck even another println and you will see the result. One thing to understand about Futures in Scala is that you want to compose and treat them as collections (hence there're for-comprehensions for them) and you rarely want to do something and print. If you do some db or rest IO, you are going to process the data further anyway.

There's an old but gold blog series by Daniel Westheide that you could read. http://danielwestheide.com/blog/2013/01/09/the-neophytes-guide-to-scala-part-8-welcome-to-the-future.html

查看更多
登录 后发表回答