We have upgraded one component from play(scala) 2.4.6 to 2.5.8. After upgrade, when we deployed the build on production, we observed significant increase in response time while uploading files(API allows client to upload images). To dig out more, I created few clients which can upload-image at high-rate(2K uploads per minutes) and found that:
If client sends upload-image requests from AWS, then image-upload API has low response time.
If client sends upload-image requests from local-network, then image-upload API has high response time.
To confirm this behavior, we deployed build again on production started sending image-upload requests using client. With server side logs, we could see that image-upload requests which were sent by our clients(deployed on AWS) were consuming less time compared to other requests which were coming from real clients i.e. cameras(which used local network).
def uploadImage(custId: String, devId: String) = Action.async(parse.multipartFormData) { implicit request =>
val startT = System.currentTimeMillis()
authenticateRole(Device, Admin) { implicit session =>
authenticateVendor {
authenticateDevice(custId, devId) {
val timestamp = System.currentTimeMillis()
Future {
val imageFile = new File(s"$pathToImageDirectory/$devId/$timestamp.jpg")
if (!imageFile.getParentFile.exists())
imageFile.getParentFile.mkdirs()
if (request.body.files != null && !request.body.files.isEmpty) {
val image = request.body.files.head.ref.file
org.apache.commons.io.FileUtils.copyFile(image, imageFile, false)
val totalT = System.currentTimeMillis() - startT
Logger.info(s"image-upload for [${request.uri}] took [$totalT] milli-seconds")
Ok(<response><status>success</status></response>)
} else {
BadRequest()
}
} recover {
case ex: IOException =>
InternalServerError()
}
}
}
}
}
With logs its already clear that controller method takes very less time and in filter log message we can see high response time. I suspect that there might be change in way how play used to parse request body because request body parsing is completed before controller method gets invoked.
I have also verified that there are enough thread in thread-pool for Future's execution(other APIs which using Future are having less response time).
As a simple test, I created new scala-play project and added API to upload-file and observed exactly above behavior.
Has anybody observed similar behavior? Any kind of help/suggestions to fix this will be appreciated.
NOTE:
1. We use new-relic agent(3.40.0) to monitor response time.
2. Scala 2.11.7 is used.
3. We have logs in filters which tells about time consumed while serving each request. This time matches with what new-relic shows.
4. We have added more messages in controller method which tells about time consumed by controller method. This time is significantly less compared to time logged in filters or new-relic reports.
5. Image size in upload request is less than 100 KB.