Проблемы загрузки / выгрузки файлов в akka-http/akka-streams
Я пытаюсь использовать akka-streams, akka-http и библиотеку alpakka для загрузки / выгрузки файлов в Amazon S3. Я вижу две проблемы, которые могут быть связаны...
- Я могу загружать только очень маленькие файлы, самый большой из которых 8 КБ.
Я не могу загрузить файлы большего размера. Это не с сообщением
Ошибка во время обработки запроса: "Источник не был материализован за 5000 миллисекунд". Завершение ответа 500 Внутренняя ошибка сервера. Чтобы изменить поведение обработки исключений по умолчанию, предоставьте пользовательский ExceptionHandler. akka.stream.impl.SubscriptionTimeoutException: Подпоток Источник не был материализован в 5000 миллисекунд
Вот мои маршруты
pathEnd {
post {
fileUpload("attachment") {
case (metadata, byteSource) => {
val writeResult: Future[MultipartUploadResult] = byteSource.runWith(client.multipartUpload("bucketname", key))
onSuccess(writeResult) { result =>
complete(result.location.toString())
}
}
}
}
} ~
path("key" / Segment) {
(sourceSystem, sourceTable, sourceId) =>
get {
val result: Future[ByteString] =
client.download("bucketname", key).runWith(Sink.head)
onSuccess(result) {
complete(_)
}
}
}
Попытка загрузить файл, скажем, 100 КБ приведет к извлечению усеченной версии файла обычно размером около 16-25 КБ. Любая помощь приветствуется
Изменить: Для проблемы загрузки я принял предложение Стефано и получил
[error] found : akka.stream.scaladsl.Source[akka.util.ByteString,akka.NotUsed]
[error] required: akka.http.scaladsl.marshalling.ToResponseMarshallable
Это заставило это работать
complete(HttpEntity(ContentTypes.`application/octet-stream`, client.download("bucketname", key).runWith(Sink.head)))
1 ответ
1) По вопросу загрузки: по телефону
val result: Future[ByteString] =
client.download("bucketname", key).runWith(Sink.head)
Вы передаете все данные из S3 в память, а затем отправляете результат.
Akka-Http как поддержка потоковой передачи, которая позволяет передавать потоковые байты прямо из источника, не буферизуя их все в памяти. Более подробную информацию об этом можно найти в документации. Практически это означает, что complete
Директива может принять Source[ByteString, _]
, как в
...
get {
complete(client.download("bucketname", key))
}
2) По вопросу загрузки: вы можете попробовать настроить Akka HTTP akka.http.server.parsing.max-content-length
установка:
# Default maximum content length which should not be exceeded by incoming request entities.
# Can be changed at runtime (to a higher or lower value) via the `HttpEntity::withSizeLimit` method.
# Note that it is not necessarily a problem to set this to a high value as all stream operations
# are always properly backpressured.
# Nevertheless you might want to apply some limit in order to prevent a single client from consuming
# an excessive amount of server resources.
#
# Set to `infinite` to completely disable entity length checks. (Even then you can still apply one
# programmatically via `withSizeLimit`.)
max-content-length = 8m
Результирующий код для проверки этого будет примерно таким:
withoutSizeLimit {
fileUpload("attachment") {
...
}
}