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