Play Framework [2.2-scala]: создание Enumerator из медленного InputStream

Я внедряю API доставки файлов AWS S3. Я вынужден передавать байты из S3ObjectInputStream S3 в браузер. У нас есть вариант использования, когда обслуживать файл с облачным фронтом не вариант (в основном локальная разработка)

У меня есть InputStream, поэтому наиболее очевидным было бы использовать Ok.chunked с Enumerator.fromStream(), но Enumerator.fromStream() имеет очень четкое предупреждение о том, что поток не должен быть медленным. Я предполагаю, что AWS S3ObjectInputStream, вероятно, является одним из самых медленных потоков.

http://www.playframework.com/documentation/2.2.x/api/scala/index.html#play.api.libs.iteratee.Enumerator%24

def fromStream(input: InputStream, chunkSize: Int = 1024 * 8)
              (implicit ec: ExecutionContext): Enumerator[Array[Byte]]

Create an enumerator from the given input stream.

This enumerator will block on reading the input stream, in the default iteratee
thread pool. Care must therefore be taken to ensure that this isn't a 
slow stream. If using this with slow input streams, consider setting the value
of iteratee-threadpool-size to a value appropriate for handling the blocking.

Поэтому мне было интересно, какой самый безопасный способ избежать голодания потока и получить потоковую передачу файла в браузер, не удерживая весь файл в памяти.

Есть ли другой способ получить Enumerator (или что-то, что мы можем отправить в результате) из InputStream?


person Jaap    schedule 23.12.2013    source источник
comment
Другим вариантом использования может быть пользовательская авторизация объектов в S3, тогда вам все равно нужно передавать байты...   -  person Jaap    schedule 23.12.2013
comment
Может быть, вы можете использовать unfoldM?   -  person Sjoerd Visscher    schedule 24.12.2013
comment
Вы нашли какое-нибудь решение?   -  person nachokk    schedule 19.05.2014
comment
Этот кусок кода работает, и я считаю, что он будет достаточно быстрым, проблема с медленным. Enumerator[Array[Byte]] позволяет разбивать вывод на части, так насколько медленным будет проблема? Мы используем этот конкретный фрагмент кода только в режиме разработки. Если вы запускаете такую ​​схему в продакшене, я бы посоветовал вместо этого использовать что-то вроде облачного фронта.   -  person Jaap    schedule 19.05.2014


Ответы (1)


Я действительно как-то неправильно прочитал документацию. Enumerator.fromStream имеет неявный ExecutionContext, который вы можете предоставить.
Если вы создадите выделенный контекст для этого конкретного типа операций, вы все равно можете столкнуться с голоданием потока, но вы контролируете, какой пул потоков вызовет эту проблему.

Мы используем игру! поэтому мы можем просто настроить пулы потоков akka в нашем application.conf:

# this is a root value in the application.conf, but you can put it anywhere
# as long as you provide the full path to the .lookup() function
my-contexts {
  s3-streaming {
    fork-join-executor {
      parallelism-min = 50
      parallelism-max = 50
    }
  }
}

и использовать их в коде следующим образом:

object MyContexts {
  val s3Streaming: ExecutionContext = 
    Akka.system.dispatchers.lookup("my-contexts.s3-streaming")
}

...

Enumerator.fromStream(stream)(MyContexts.s3Streaming)
person Jaap    schedule 04.06.2014