1

I'm working with akka dataflow and I'd like to know if there is a way to cause a particular block of code to wait for the completion of a future, without explicitly using the value of that future.

The actual use case is that I have a file and I want the file to be deleted when a particular future completes, but not before. Here is a rough example. First imagine I have this service:

trait ASync {
   def pull: Future[File]
   def process(input : File): Future[File]
   def push(input : File): Future[URI]
}

And I have a workflow I want to run in a non-blocking way:

val uriFuture = flow {
    val pulledFile = async.pull(uri)
    val processedile = async.process(pulledFile())
    val storedUri = async.push(processedFile())

    // I'd like the following line executed only after storedUri is completed, 
    // not as soon as pulled file is ready.
    pulledFile().delete()

    storedUri()
}
Dave DeCaprio
  • 2,051
  • 17
  • 31

2 Answers2

1

You could try something like this:

val uriFuture = flow {
  val pulledFile = async.pull(uri)
  val processedile = async.process(pulledFile())
  val storedUri = for(uri <- async.push(processedFile())) yield {
    pulledFile().delete()
    uri
  }
  storedUri()
}

In this example, pulledFile.delete will only be called if the Future from push succeeds. If it fails, delete will not be called. The result of the storedUri future will still be the result of the call to push.

Or another way would be:

val uriFuture = flow {
  val pulledFile = async.pull(uri)
  val processedile = async.process(pulledFile())
  val storedUri = async.push(processedFile()) andThen{
    case whatever => pulledFile().delete()
  }
  storedUri()
}

The difference here is that delete will be called regardless of if push succeeds or fails. The result of storedUri still will be the result of the call to push.

cmbaxter
  • 35,283
  • 4
  • 86
  • 95
  • The problem is that if I try to put pulledFile() inside any block that passed to a function on the Future returned from async.push, I get a ton of compile errors. However, I found I do get it to compile if I assign pulledFile() to a val outside the block and then use it within the block. I'll check if that runs correctly and then update the answer. – Dave DeCaprio May 27 '13 at 13:37
0

You can use callbacks for non-blocking workflow:

future onSuccess {
  case _ => file.delete() //Deal with cases obviously... 

}

Source: http://doc.akka.io/docs/akka/snapshot/scala/futures.html

Alternatively, you can block with Await.result:

val result = Await.result(future, timeout.duration).asInstanceOf[String]

The latter is generally used when you NEED to block - eg in test cases - while non blocking is more performant as you don't park a thread to spin up another thread only to resume the other thread again - that's slower than an asynchronous activity because of the resource management overhead.

The typesafe staff are calling it "Reactive". That's a little bit of a buzzword. I would laugh if you used it in the workplace.

JasonG
  • 5,794
  • 4
  • 39
  • 67