I have a simple alpakka s3 file downloading on top of Play framework 2.8, the code is like this:
in S3 service:
def download(link: String): Source[Option[(Source[ByteString, NotUsed], ObjectMetadata)], NotUsed] = {
S3.download(TraktrainBucket.DOWNLOAD_BUCKET, link)
}
and in a controller:
val source = s3Service.download(link).map(s => s.map(_._1))
val trackName = "track name"
val filename = trackName.replaceAll("[^A-Za-z0-9 \\-.]", "") + (if (track.drumKit) ".zip" else ".mp3")
val disposition = "attachment; filename=\"" + filename + "\""
Result(
header = ResponseHeader(200, Map("Content-Disposition" -> disposition)),
body = HttpEntity.Streamed(source.flatMapConcat(_.getOrElse(Source.empty)), None, Some("application/octet-stream"))
)
Also I've an upload thing (it takes an mp3 file, process it with ffmpeg and uploads it to s3 like that:
def richUploadMp3(extension: String, checkFunction: (String, Option[String]) => Boolean, cannedAcl: CannedAcl, bucket: String) = producerAction(parse.multipartFormData(handleFilePartAsFile)).async { implicit request =>
val s3Filename = request.user.get.id + "/" + java.util.UUID.randomUUID.toString + "." + extension
val s3FilenameTagged = request.user.get.id + "/" + java.util.UUID.randomUUID.toString + "." + extension
val fileOption = request.body.file("file").map {
case FilePart(key, filename, contentType, file, _, _) =>
logger.info(s"key = ${key}, filename = ${filename}, contentType = ${contentType}, file = $file")
if(checkFunction(filename, contentType)) {
val taggedFile = audioService.putTag(file)
for {
mp3 <- FileIO.fromPath(file.toPath).runWith(s3Service.uploadSink(s3Filename, cannedAcl, TraktrainBucket.DOWNLOAD_BUCKET))
mp3Tagged <- FileIO.fromPath(taggedFile.toPath).runWith(s3Service.uploadSink(s3FilenameTagged, cannedAcl, TraktrainBucket.STREAMING_BUCKET))
} yield (mp3, mp3Tagged, file, taggedFile)
} else {
throw new Exception("Upload failed")
}
}
fileOption match {
case Some(opt) => opt.map(o => {
o._3.delete()
o._4.delete()
Ok(Json.toJson(Seq(s3Filename, s3FilenameTagged)))
})
case _ => Future.successful(BadRequest("ERROR"))
}
}
And it works fine for some time but after like 2 days It starts throwing this error:
exceeded configured max-open-requests value of 1024
and it's not getting away, it seems akka just open requests and do not close it
My akka-http conf looks like this:
akka {
loglevel = DEBUG
http {
client {
connecting-timeout = 5 s
idle-timeout = 5 s
parsing {
max-content-length = 3000m
}
}
server {
parsing {
max-content-length = 3000m
}
}
host-connection-pool {
max-open-requests = 1024
idle-timeout = 10 s
client {
connecting-timeout = 10 s
idle-timeout = 10 s
}
}
}
}
and sometimes I see such thigs in my logs:
Response stream for [GET /free/642241] failed with 'TCP idle-timeout encountered on connection to [s3.us-west-2.amazonaws.com:443], no bytes passed in the last 10 seconds'. Aborting connection.
what's the problem here not closing connections? How could I monitor it? I didn't even find any way to track open-requests over the time, and how could I fix it?
My alpakka in build.sbt looks like this:
val AkkaVersion = "2.5.31"
val AkkaHttpVersion = "10.1.12"
libraryDependencies ++= Seq(
"com.lightbend.akka" %% "akka-stream-alpakka-s3" % "2.0.1",
"com.typesafe.akka" %% "akka-stream" % AkkaVersion,
"com.typesafe.akka" %% "akka-http" % AkkaHttpVersion,
"com.typesafe.akka" %% "akka-http-xml" % AkkaHttpVersion
)