Scala Future oncomplete doesn't complete? [duplicate] - scala

This question already has answers here:
Wait until all Future.onComplete callbacks are executed
(2 answers)
Closed 5 years ago.
I am trying to understand higher order functions in scala futures. I wrote this piece of code
import scala.concurrent.Future
import scala.util.{Failure, Success}
import scala.concurrent.ExecutionContext.Implicits.global
object App30 extends App {
def getMilk(): String = {
val ans = "5 gallons of milk"
ans
}
def getFlour(): String =
{
val ans= "2 oz of flour"
ans
}
val milkFuture = Future { getMilk() }
val flourFuture = Future { getFlour() }
val resultFut = {
for {
milk <- milkFuture
flour <- flourFuture
result = milk + flour
} yield result
}
resultFut.onComplete{
case Success(answer) => println("The result of getting ingridents is " + answer)
case Failure(exception) => println("could not access future value")
}
}
My issue is that I am not able to get the required string 'the result of getting ...' . I see that the debugger stops with onComplete and does not proceed to successful case.
May I know where I am going wrong? If this was a silly mistake, kindly point it out and I will take down the question after that. Else, provide with an explanation on what concept is amiss as this will help newcomers.
Thanks

You have to explicitly block on the future, otherwise the main thread might terminate before its completion:
import scala.concurrent.{Await, Future}
import scala.concurrent.duration._
Await.result(resultFut, 5 seconds)
Note such methods should definitely not be used with production code, it is merely for testing the output of the Future. Usually, you'll have some event loop running endlessly in the background where the future will have a chance to complete, unless something bad happens.

Related

Future onComplete works every other time [duplicate]

This question already has answers here:
Flaky onSuccess of Future.sequence
(2 answers)
Closed 3 years ago.
I'm experimenting with futures. So i created a huge list of random numbers and then separated it in 3 groups to run them parallelly with some code
val itemsInGroup = 500000
val numbers: List[Int] = 1.to(1500000).map(v => Random.nextInt(20)).toList
val groups: List[List[Int]] = numbers.grouped(itemsInGroup).toList.take(3)
val future = Future.sequence(groups.map(gr => Future[Int] {countSum(gr)}))
future andThen {
case Success(threeNumbers) => println(threeNumbers)
}
what makes countSum is not too much important, just to take time i use this code
case class Person(name: String, age: Int) {
def age10: Int = age - age % 10
}
def countSum(lst: List[Int]): Int = lst.map(v => Person("John", v).age10).sum
as a result of a future i print list of 3 numbers. The problem is it doesnt work every time. Sometimes andThen works sometimes not, and if i change itemsInGroup value to small amounts, it works more frequently than big amounts of elements. So i suspect that there's a kind of implicit timeout or something otherwise i can't explain such phenomen.
Please, your tips appreciated
UPD Actually so much code were not needed, even simple example
val ft = Future {
Thread.sleep(10)
10
}
ft andThen {
case Success(value) => println("Here i work")
}
works the same way - sometimes works sometimes not, the more delay the less possibility that it will complete
Your main app thread is probably being terminated before your future completes. Try the following code.
import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Success, Failure}
val future = Future {
Thread.sleep(10)
10
}
val result = future andThen {
case Success(value) => println("Here i work")
case Failure(ex) => println(s"Error: ${ex.getMessage}")
}
println(Await.result(result, Duration.Inf)) // Only if you are sure it will ever finish, still it is recommended to use an appropriate timeout.

I get inconsistent results from Monix firstOptionL - race condition?

I get an intermittent missing value from repeated calls to the same (MongoDB) database call which I've converted into an Observable. I've removed all database code to get a minimal test case which only has the Monix bits and I'm still missing values occasionally - usually one or two per 2,000 tests.
According to the docs ConcurrentSubject means "one doesn't need to follow the back-pressure contract", but I get similar failures whether I do or not.
import monix.eval.Task
import monix.reactive.{MulticastStrategy, Observable}
import monix.reactive.subjects.ConcurrentSubject
import org.scalatest.FunSuite
import scala.concurrent.Await
import scala.concurrent.duration.Duration
class Test_JustMonix extends FunSuite {
implicit val scheduler = monix.execution.Scheduler.global
def build(): Observable[Boolean] = {
val subject = ConcurrentSubject(MulticastStrategy.publish[Boolean])
subject.doAfterSubscribe {
Task.eval {
subject.onNext(true)
subject.onComplete()
}
}
}
test("just monix") {
(0 until 20).foreach { loop =>
println(s"loop $loop")
val tOpts = (0 until 100).map { _ => build().firstOptionL }
val tDone = Task.gather(tOpts).map { list =>
val emptyCount = list.count(_.isEmpty)
assert(emptyCount === 0)
}
Await.result(tDone.runToFuture, Duration.Inf)
}
println("Finished")
}
}
On some runs, all 20x100 loops complete correctly - firstOptionL isDefined for all 2,000 results. However, more than 50% of the time the assert(emptyCount === 0) triggers when the value is 1 or sometimes 2, indicating that occasionally I am getting a None value, as if onComplete was occurring before onNext?
This can happen in any of the 20 loops, so it looks like either a race condition or I am misunderstanding the required input. I've tried pretty much all subjects - PublishSubject, with and without BufferedSubscriber and all give similar results.
I've also tried delaying the onComplete until the Ack via
subject.onNext(true).map(_=> subject.onComplete())
and that seems to be fail slightly sooner.
I've also tried MulticastStrategy.replay with no difference.
I'm using Monix 3.0.0-RC3 on Scala 2.12.8.

Get actual value in Future Scala [duplicate]

I am a newbie to scala futures and I have a doubt regarding the return value of scala futures.
So, generally syntax for a scala future is
def downloadPage(url: URL) = Future[List[Int]] {
}
I want to know how to access the List[Int] from some other method which calls this method.
In other words,
val result = downloadPage("localhost")
then what should be the approach to get List[Int] out of the future ?
I have tried using map method but not able to do this successfully.`
The case of Success(listInt) => I want to return the listInt and I am not able to figure out how to do that.
The best practice is that you don't return the value. Instead you just pass the future (or a version transformed with map, flatMap, etc.) to everyone who needs this value and they can add their own onComplete.
If you really need to return it (e.g. when implementing a legacy method), then the only thing you can do is to block (e.g. with Await.result) and you need to decide how long to await.
You need to wait for the future to complete to get the result given some timespan, here's something that would work:
import scala.concurrent.duration._
def downloadPage(url: URL) = Future[List[Int]] {
List(1,2,3)
}
val result = downloadPage("localhost")
val myListInt = result.result(10 seconds)
Ideally, if you're using a Future, you don't want to block the executing thread, so you would move your logic that deals with the result of your Future into the onComplete method, something like this:
result.onComplete({
case Success(listInt) => {
//Do something with my list
}
case Failure(exception) => {
//Do something with my error
}
})
I hope you already solved this since it was asked in 2013 but maybe my answer can help someone else:
If you are using Play Framework, it support async Actions (actually all Actions are async inside). An easy way to create an async Action is using Action.async(). You need to provide a Future[Result]to this function.
Now you can just make transformations from your Future[List[Int]] to Future[Result] using Scala's map, flatMap, for-comprehension or async/await. Here an example from Play Framework documentation.
import play.api.libs.concurrent.Execution.Implicits.defaultContext
def index = Action.async {
val futureInt = scala.concurrent.Future { intensiveComputation() }
futureInt.map(i => Ok("Got result: " + i))
}
You can do something like that. If The wait time that is given in Await.result method is less than it takes the awaitable to execute, you will have a TimeoutException, and you need to handle the error (or any other error).
import scala.concurrent._
import ExecutionContext.Implicits.global
import scala.util.{Try, Success, Failure}
import scala.concurrent.duration._
object MyObject {
def main(args: Array[String]) {
val myVal: Future[String] = Future { silly() }
// values less than 5 seconds will go to
// Failure case, because silly() will not be done yet
Try(Await.result(myVal, 10 seconds)) match {
case Success(extractedVal) => { println("Success Happened: " + extractedVal) }
case Failure(_) => { println("Failure Happened") }
case _ => { println("Very Strange") }
}
}
def silly(): String = {
Thread.sleep(5000)
"Hello from silly"
}
}
The best way I’ve found to think of a Future is a box that will, at some point, contain the thing that you want. The key thing with a Future is that you never open the box. Trying to force open the box will lead you to blocking and grief. Instead, you put the Future in another, larger box, typically using the map method.
Here’s an example of a Future that contains a String. When the Future completes, then Console.println is called:
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
object Main {
def main(args:Array[String]) : Unit = {
val stringFuture: Future[String] = Future.successful("hello world!")
stringFuture.map {
someString =>
// if you use .foreach you avoid creating an extra Future, but we are proving
// the concept here...
Console.println(someString)
}
}
}
Note that in this case, we’re calling the main method and then… finishing. The string’s Future, provided by the global ExecutionContext, does the work of calling Console.println. This is great, because when we give up control over when someString is going to be there and when Console.println is going to be called, we let the system manage itself. In constrast, look what happens when we try to force the box open:
val stringFuture: Future[String] = Future.successful("hello world!")
val someString = Future.await(stringFuture)
In this case, we have to wait — keep a thread twiddling its thumbs — until we get someString back. We’ve opened the box, but we’ve had to commandeer the system’s resources to get at it.
It wasn't yet mentioned, so I want to emphasize the point of using Future with for-comprehension and the difference of sequential and parallel execution.
For example, for sequential execution:
object FuturesSequential extends App {
def job(n: Int) = Future {
Thread.sleep(1000)
println(s"Job $n")
}
val f = for {
f1 <- job(1)
f2 <- job(2)
f3 <- job(3)
f4 <- job(4)
f5 <- job(5)
} yield List(f1, f2, f3, f4, f5)
f.map(res => println(s"Done. ${res.size} jobs run"))
Thread.sleep(6000) // We need to prevent main thread from quitting too early
}
And for parallel execution (note that the Future are before the for-comprehension):
object FuturesParallel extends App {
def job(n: Int) = Future {
Thread.sleep(1000)
println(s"Job $n")
}
val j1 = job(1)
val j2 = job(2)
val j3 = job(3)
val j4 = job(4)
val j5 = job(5)
val f = for {
f1 <- j1
f2 <- j2
f3 <- j3
f4 <- j4
f5 <- j5
} yield List(f1, f2, f3, f4, f5)
f.map(res => println(s"Done. ${res.size} jobs run"))
Thread.sleep(6000) // We need to prevent main thread from quitting too early
}

Why does my simple scala object hangs for a minute or so while it includes a future

I am learning scala futures and I hit my question already. I have a very simple example
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.util.{Failure, Success}
/**
* Created by dummy on 05/02/15.
*/
object FutureUtils extends App{
val f = Future {
Thread.sleep(1000)
println("I am learning scala futures")
"learning"
}
f onComplete {
case Success(value:String) => println("got the response back")
case Failure(t: Throwable) => println("did not expect this")
}
println("I am still learning")
}
When I run the program as-is output never prints
got the response back
instead looks like it hangs for a minute or so and ends without printing the expected output ever. I am sure I am missing something very basic here.
I also tried adding System.in.read() at the end and it seems when I input any dummy value, programs ends printing expected result. What is the reason behind this behavior? Could anyone please help me understand this?
The reason the program doesn't work without the System.in.read() is that onComplete does not block until the future completes but merely adds a callback for when it does. That callback never gets executed because the whole program ends before the future completes. To fix this problem, you could deliberately let the main thread go into an infinite loop and explicitly terminate the process in the callback.
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.util.{Failure, Success}
object Main extends App {
val f = Future {
Thread.sleep(1000)
println("I am learning scala futures")
"learning"
}
f onComplete {
case Success(value:String) => println("got the response back"); System.exit(0)
case Failure(t: Throwable) => println("did not expect this"); System.exit(1)
}
println("I am still learning")
while (true){
Thread.sleep(1000)
}
}
You need to await the future, the program is exiting before it completes.
import scala.concurrent.Await
import scala.concurrent.duration._
var myFuture = Future {
Thread.sleep(1000)
1
}
// oncomplete handlers, etc here
println(Await.result(myFuture, 5 seconds))
EDIT: If you must use onComplete and can't verify that those handlers are executed before Await.ready/result then you should use formal synchronization, i.e.:
import scala.concurrent._
import java.util.concurrent.CountDownLatch
object Main extends App {
val f = Future {
Main.synchronized {
Thread.sleep(1000);
1
}
}
val latch = new CountDownLatch(1)
f.onComplete {
case _ => { latch.countDown() }
}
latch.await()
}
Well... since you are sleeping for 1000 miliseconds inside your future, your future will take at least 1 second to complete. The app thread completes itself and exits in this time.
You have to make sure that the app thread is alive when the future completes. You can do this by sleeping in your app thread for some time... like this.
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.util.{Failure, Success}
object FutureUtils extends App{
val f = Future {
Thread.sleep(1000)
println("I am learning scala futures")
"learning"
}
f onComplete {
case Success(value:String) => println("got the response back")
case Failure(t: Throwable) => println("did not expect this")
}
// Wait for some time
// Not sure future will complete in this time or not
Thread.sleep(1000);
Thread.sleep(1000);
Thread.sleep(1000);
}
But, the better way to do this is by making it so that the app thread needs the future to complete.
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.util.{ Failure, Success }
object FutureUtils extends App {
val f = Future {
Thread.sleep( 1000 )
println( "I am learning scala futures" )
"learning"
}
f onComplete {
case Success( value:String ) => println( "got the response back" )
case Failure( t: Throwable ) => println( "did not expect this" )
}
while ( f.value == None ) {
// Waste time just till the future is complete.
}
// Do something with future value.
f.foreach( ( s: String ) => println( s ) )
}

Scala: Future in action

I'm confused about how Scala Future works. Can someone explain what's wrong with code:
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
val numbers = List(1,2,3,4,5,6,7,8,9,10)
def showNumbers() = {
numbers
}
val futueNumber = future {
showNumbers.filter((a: Int) => a % 2 == 0)
}
futueNumber onSuccess {
case resultList => resultList
}
futueNumber
I expect to receive a result:
List(1,2,3,4,5,6,7,8,9,10)
But REPL outputs:
res1: scala.concurrent.Future[List[Int]] = scala.concurrent.impl.Promise$DefaultPromise#3644febc
Please, give me a short hint, how to fix this
The simple answer is that you need to await the future for you example to work:
val result = Await.result(futureNumber, 1.second)
However, the purpose of future's is not to block on asynchronous work, as Await does, but instead to use the result of the future when becomes available.
The key to using future is understanding that it does not actually hold the value of your computation, but rather is promise that at some point in the future, it will provide that value.
The usual use case is a request coming into a server that requires some work, which may take some time and itself wait on IO, like this:
def receiveMsg(msg: String, caller: Caller) = {
doSomeAsyncWork(msg).map(response => caller.send(response)
}
I.e. you are called with an object that has a send method that you want to call when doSomeAsyncWork is done, but you don't want to block the current thread until that future completes. Instead you map the future, which means that response => caller.send(response) will be called for you when doSomeAsyncWork is done.
futureNumber is of type Future[List[Int]], since you defined it as such in
val futureNumber = future {
showNumbers.filter((a: Int) => a % 2 == 0)
}
Therefore, when you print futureNumber, that is what gets printed. The variable does not get reassigned to the future value! If you want to print the value of the future, you need to do it inside the onSucess callback:
futureNumber onSuccess {
case resultList => println(resultList)
}
Alternatively, you can block waiting for the future with
import scala.concurrent.ExecutionContext.Implicits.global
import duration._
val theList = scala.concurrent.Await.result(futureNumber, 10 seconds)
println(theList)
Although this might not work if done in the REPL.
The whole point of the Future type is that it acts as a marker that alerts you to the presence of concurrency and should help you handle it better.