Given this example code from Play documentation:
def upload = Action(parse.temporaryFile) { request =>
request.body.moveTo(new File("/tmp/picture/uploaded"))
Ok("File uploaded")
}
How 100 simultaneous slow upload requests will be handled (number of threads)?
It depends. The number of actual threads being used isn't really relevant. By default, Play uses a number of threads equal to the number of CPU cores available. But this doesn't mean that if you have 4 cores, you're limited to 4 concurrent processes at once. HTTP requests in Play are processed asynchronously in a special internal ExecutionContext
provisioned by Akka. Processes running in an ExecutionContext
can share threads, so long as they are non-blocking--which is abstracted away by Akka. All of this can be configured in different ways. See Understanding Play Thread Pools.
The Iteratee
that consumes the client data must do some blocking in order to write the file chunks to disk, but done in small (and fast) enough chunks, this shouldn't cause other file uploads to become blocked.
What I would be more worried about is the amount of disk I/O your server can handle. 100 slow uploads might be okay, but you can't really say without benchmarking. At some point you will run into trouble when the client input exceeds the rate that your server can write to disk. This will also not work in a distributed environment. I almost always choose to bypass the Play server entirely and direct uploads to Amazon S3.
Will be uploaded file buffered in memory or streamed directly to disk?
All temporary files are streamed to disk. Under the hood, all data sent from the client to the server is read using the iteratee library asynchronously. For multipart uploads, it is no different. The client data is consumed by an Iteratee
, which streams the file chunks to a temporary file on disk. So when using the parse.temporaryFile
BodyParser
, request.body
is just a handle to a temporary file on disk, and not the file stored in memory.
It is worth noting that while Play can handle those requests in a non-blocking manner, moving the file once complete will block. That is, request.body.moveTo(...)
will block the controller function until the move is complete. This means that if several of the 100 uploads complete at about the same time, Play's internal ExecutionContext
for handling requests can quickly become overloaded. The underlying API of moveTo
is also deprecated in Play 2.3, as it uses FileInputStream
and FileOutputStream
to copy the TemporaryFile
to a permanent location. The docs advise you to use the Java 7 File API, instead, as it is much more efficient.
This may be a little crude, but something more like this should do it:
import java.io.File
import java.nio.file.Files
def upload = Action(parse.temporaryFile) { request =>
Files.copy(request.body.file.toPath, new File("/tmp/picture/uploaded").toPath)
Ok("File uploaded")
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With