0
votes

I'm playing with the idea of building a FutureBuilder class to possibly simplify chaining Futures. In the process I'm trying to understand the consequences of using Await.

So If I have Mappers that go something like this F1(future1) -> F2 -> F3

F1: Builds object Foo

F2: Goes to the DB to add a value Bar to Foo

F3: Sends a message containing Foo to somewhere else

The problem I have is with F2, where typically I would create a Future to get Bar from the DB. In this case I'm already in a Future so it's easier to just an Await.result() on the sub-future, so that I can immediately add it to Foo and pass it on to F3.

Is there a problem with that? since I'm it's alreayd in a future am I locking an additional thread by waiting?

OR is there a different pattern entirely I should do? Keep in mind I want to be able to keep going so have the Foo object passed on in the mapper so that I can easily add F4,5,6,etc. I know I could also move F3 into F2 and map with the DB request but that would also mean I have to move F4,5,6,etc. with it?

2

2 Answers

0
votes

Is there a problem with that? since I'm it's alreayd in a future am I locking an additional thread by waiting?

Yes, you are blocking an addition thread: http://doc.akka.io/docs/akka/current/java/futures.html#use-with-actors

Warning

Await.result and Await.ready are provided for exceptional situations where you must block, a good rule of thumb is to only use them if you know why you must block.

I only ever use Await in test code.

The section below in that document describes how to chain futures together. If you can use Java 8, it becomes even nicer, details in this section:

http://doc.akka.io/docs/akka/current/java/futures.html#java-8-completionstage-and-completablefuture

0
votes

If the object construction involves multiple stages and multiple blocking calls like DB calls, if the blocking calls are really a concern then, Rather than chaining multiple futures, I wonder why dont you use actors. Foo can be the actor's State.

object Data {
    case class Foo(var1: String, var2: String, ..)

    // commands or messages 
    case object doF1
    case object doF2
    //...
}

class FutureChainAlternative extends Actor {
    def receive = {
        case doF1 =>
            // perform what F1 should do.
            // pipe the result back to self
            f1.map(f1Result => preferredFormatConvertorOrProcessorForF1) pipeTo self         

         case preferredFormatConvertorOrProcessorF1 =>
            // update the Foo object with F1 results
            self ! doF2   

         case doF2 =>
            // perform what F2 should do.
            // pipe the result back to self
            f2.map(f2Result => preferredFormatConvertorOrProcessorForF2) pipeTo self    
    }
}

Why we need a separate message preferredFormatConvertorOrProcessorF1 ? F1 on completion will be resolved in a separate thread. We cannot update actors state in that another thread. ( well known closing over problem )

Timeouts if you need things to happen within a specific time frame. Ask pattern combined with Pipe pattern will do the magic.