Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Play framework, when to use Promises to handle a request and when not to?

I am new to Play As I understand,it might be wrong, play framework is non-blocking by handling requests in an async manner, long blocking operations should be done asynchronously using promises. So when should I use promise or mapped promises to handle a given request and when not to?

For example, suppose a user uploads a file, when it gets to the controller, I move the file from the temp folder to a desired folder and insert a database record. So this involves 2 blocking operations, the file moving and inserting to database. Suppose the file is not large, say 10MB max, so the file moving should be resonably fast. And inserting a db record should be fast as well with a blocking database driver.

In this simple case, Should I use one promise/future to do the 2 operations or 2 mapped promises(move file then insert db record) or do not use promise at all? And why?

Please share your thoughts/experiences. Thank you in advance.

like image 584
Kevin Avatar asked Aug 05 '13 09:08

Kevin


1 Answers

It's actually a fine line, and deciding what goes into a future and what doesn't ends up being quite application-dependent.

In general, you shouldn't need to worry about putting database calls in a future. Since the underlying driver is blocking, you will be blocking somewhere, even if you put it in a future or an actor. So: try to decrease db latency. Make sure your database is close by (network topologically speaking) and has sufficient resources.

Moving the file in a non-blocking manner can be fairly trivially handled with something like:

def uploadFile() = Action {
  Async {
    // handle file moving
    Ok
  }
}

Let's say, however, you still have two expensive things to do with the file. If one action is dependent on the other, then you can organize it however you'd like (in one Future is perfectly fine). You have to finish the first task before starting the second. The code may be cleanest, however, using two futures. High level, something like:

for { movedFile <- moveFile(file)
  analyzedFile <- analyzeFile(movedFile) } yield analyzedFile

seems clean to me. But don't feel that you have to split every tiny action into its own Future.

However, if you have two tasks that can run independently, then you can certainly use two futures to do both at the same time.

like image 131
Andrew Conner Avatar answered Oct 03 '22 21:10

Andrew Conner