LoginSignup
3
3

More than 5 years have passed since last update.

Stream 移行ガイド / Play2.6【翻訳】

Last updated at Posted at 2017-06-16

Play framework 2.5.x : Stream 移行ガイド を google 翻訳した。(websocket/Commet/EventSource は使ってないので未訳)


Streams移行ガイド

Play 2.5では、データとレスポンスの本体をどのようにストリームするかが大きく変わっています。

  1. Play 2.5では、 ストリーミング用のAkkaストリーム が使用されます。以前のバージョンのPlayでは、 WebSocketChunks など、いくつかの特別な種類のストリーミングだけでなく、ストリーミングにiteratees を使用していました。

    Akkaストリームに変更する主なメリットは2つあります。まず、JavaユーザーはPlayの全機能セットにアクセスできるようになりました。ボディーパーサとフィルタを記述できます。次に、ストリーミングライブラリはPlay全体でより一貫性があります。

  2. Play 2.5は バイトのパケットを保持するために ByteString を使用します。以前は、Playはバイト配列( byte[] / ArrayByte)を使っていました。

    ByteString クラスはJavaの String のように不変ですので、安全で使いやすいです。 String と同様に、構築時にデータをコピーするため、パフォーマンスコストは小さくなりますが、これは安価な連結および部分文字列演算とのバランスが取れています。

  3. Play 2.5は レスポンスボディに新しい HttpEntity タイプ を持っています。これまでのレスポンスボディは、単純なバイトストリームでした。 HTTPボディは HttpEntityの一種です: StrictStreamedChunked です。

    Playにどのタイプのエンティティを使用するかを伝えることで、アプリケーションはPlayのHTTP応答の送信方法をより詳細に制御できます。また、Playが本体をどのように配信するのかを簡単に最適化することもできます。

変更の概要

Play APIの次の部分が更新されました:

  • 結果( Result本体、chunked / feed /streamメソッド)
  • アクション( EssentialAction
  • ボディパーサー( BodyParser
  • WebSocket( WebSocket
  • サーバー送信イベント( EventSource

以下のタイプが変更されました:

目的 古いタイプ 新しいタイプ
バイト保持 byte [] / 配列[Byte] ByteString
ストリーム生成 EnumeratorWebSocket.OutChunks.OutEventSource.Out Source
ストリームを別のストリームに変換する Enumeratee Flow
ストリームを単一の値に変換する Iteratee Accumulator
ストリームを消費する Iteratee Sink

移行方法(API別)

次のセクションでは、APIのさまざまな部分を使用するコードを移行する方法の概要を示します。

チャンク結果の移行( chunkedResults.Chunked

Play 2.4 では、Scalaで Enumerator 、そしてJavaで Results.Chunked オブジェクトを使用してチャンク結果を作成します。 Play 2.5では、これらのAPIの部分は引き続き使用できますが、廃止されました。

新しいAPIに移行する場合は、 StatusHeader オブジェクトで chunked メソッドを呼び出し、チャンクのストリームにAkka Streams Source オブジェクトを提供することで、チャンク結果を作成できます。

より高度なユーザは、明示的に HttpEntity.Chunked オブジェクトを作成し、それを Result オブジェクトコンストラクタに渡すことを好むかもしれません。

  • EnumeratorSource に移行する方法については、EnumeratorSource に移行する」を参照してください。

ストリーミング結果の移行( feedstream )(Scalaのみ)

Play 2.4では、Scalaユーザは Enumeratorfeed メソッドまたは stream メソッドに渡すことで結果をストリーミングできます。 (Javaユーザは、チャンクされた結果とは別に、結果をストリーミングする方法がありませんでした)。 feed メソッドは、 Enumerator のデータをストリーミングして接続を閉じました。 stream メソッドは、HTTPバージョンの接続と Content-Length ヘッダの有無に応じて、結果をストリーミングまたはチャンクして、おそらく接続を閉じました。

Play 2.5では、 streamメソッドが削除され、 feed メソッドは廃止されました。 feed メソッドを新しいAPIに移行するかどうかを選択することができます。 stream メソッドを使うとコードを変更する必要があります。

新しいAPIは、 Result オブジェクトを直接作成し、その本体を表す HttpEntity を選択することです。ストリーミングされた結果の場合、 HttpEntity.Streamed クラスを使用することができます。 Streamed
クラスは Source を本体とし、オプションの Content-Length ヘッダ値をとります。 Source の内容はクライアントに送られます。エンティティに Content-Length ヘッダがある場合、接続はオープンのままになります。そうでなければ、ストリームの終わりを知らせるために閉じられます。

  • EnumeratorSource に移行する方法については、「EnumeratorSource に移行する」を参照してください。

未訳部分

### Migrating WebSockets (`WebSocket`)
#### Migrating Scala WebSockets
#### Migrating Java WebSockets
### Migrating Comet
#### Migrating Java Comet
#### Migrating Scala Comet
### Migrating Server-Sent events (`EventSource`)
#### Migrating Java Server-Sent events
#### Migrating Scala Server-Sent events

カスタムアクションの移行( EssentialAction )(Scalaのみ)

Scalaのほとんどのユーザーは、アクションに Action クラスを使用します。 Action クラスはロジックを実行して結果を送る前に常にボディを完全に解析する EssentialAction の一種です。 ユーザは独自のカスタムEssentialActionを書いてリクエストボディーを段階的に処理するようなことをすることができます。

Play 2.4 アプリケーションで通常の Action を使用している場合は、マイグレーションは必要ありません。 しかし、もしあなたが EssentialAction を書いたのであれば、それを Play 2.5 の新しいAPIに移す必要があります。 「EssentialAction」の動作は同じですが、シグネチャは Play 2.4 から変更されました:

trait EssentialAction extends (RequestHeader => Iteratee[Array[Byte], Result])

to a new signature in Play 2.5:

trait EssentialAction extends (RequestHeader => Accumulator[ByteString, Result])

移行するには、 IterateeAccumulatorArray[Byte]ByteString で置き換える必要があります。

  • IterateeをAccumulatorに移行する方法については、「IterateesをSinks and Accumulatorsに移行する」を参照してください。
  • Array[Byte]ByteString に移行する方法については、「ByteStringsへのバイト配列の移行」を参照してください。

カスタムボディパーサーの移行( BodyParser )(Scalaのみ)

Play 2.4アプリケーションに独自のBodyParserを持っているScalaユーザーの場合は、新しいPlay 2.5 APIに移行する必要があります。 BodyParser型シグネチャは、Play 2.4では次のようになります。

trait BodyParser[+A] extends (RequestHeader => Iteratee[Array[Byte], Either[Result, A]])

In Play 2.5 it has changed to use Akka Streams types:

trait BodyParser[+A] extends (RequestHeader => Accumulator[ByteString, Either[Result, A]])

移行するには、 IterateeAccumulatorArray[Byte]ByteString で置き換える必要があります。

  • Iteratee を Accumulator に移行する方法については、「IterateesをSinks and Accumulatorsに移行する」を参照してください。
  • [Array [Byte]]をByteStringに移行する方法については、「ByteStringsへのバイト配列の移行」を参照してください。

Result ボディーの移行(Scalaのみ)

Result オブジェクトは、結果本体と接続クローズフラグの表現方法が変更されました。 body: Enumerator[Array[Byte]], connection: Connection から body: HttpEntity に取り替えることになりました。 HttpEntity 型にはボディに関する情報と接続を閉じる方法に関する暗黙の情報が含まれています。

Source とオプションの Content-LengthContent-Type ヘッダを含む Streamed エンティティを使って、既存の Enumerator を移行できます。

val bodyPublisher: Publisher[ByteString] = Streams.enumeratorToPublisher(bodyEnumerator)
val bodySource: Source[ByteString, _] = Source.fromPublisher(bodyPublisher)
val entity: HttpEntity = HttpEntity.Streamed(bodySource)
new Result(headers, entity)

これらの型への移行の詳細については、 Enumerators の移行と ByteString への移行の節を参照してください。

  • Iteratee を Accumulator に移行する方法については、「IterateesをSinks and Accumulatorsに移行する」を参照してください。
  • [Array [Byte]]をByteStringに移行する方法については、「ByteStringsへのバイト配列の移行」を参照してください。

Resultボディのストリームはまったく必要ないかもしれません。 そうであれば、ボディに Strictエンティティを使えます。

new Result(headers, HttpEntity.Strict(bytes))

移行する方法(型別)

このセクションでは、バイト配列とストリームを新しいAkka Streams APIに移行する方法について説明します。

Akka StreamsはAkkaプロジェクトの一部です。 PlayはAkka Streamsを使用してストリーミング機能を提供します。一連のバイトやその他のオブジェクトを送受信します。 Akkaプロジェクトには、Akkaストリームに関する多くの優れたドキュメントがあります。 PlayでAkka Streamsを使用する前に、利用可能な情報を確認するためにAkka Streamsのドキュメントを調べることをお勧めします。

APIドキュメントは、Akka APIの主要なドキュメントの akka.stream パッケージの下にあります:

最初にAkka Streamsを使い始めるときは、 Basics のフローの操作 セクションを見ることをお勧めします。 Akka Streams APIの最も重要な部分を紹介します。

一度にアプリケーション全体を変換する必要はありません。 アプリケーションの一部は繰り返し使用でき、他の部分はAkkaストリームを使用します。 Akka Streamsは reactive streams の実装を提供し、Playのiterateesライブラリも反応ストリームの実装を提供します。その結果、Play の iteratees は Akka Streams に簡単にラップすることができます。

バイト配列( byte[] / Array[Byte])を ByteStringに移行する

JavaScalaByteStringのAPIドキュメントを参照してください。

例:

Scala:

// Get the empty ByteString (this instance is cached)
ByteString.empty
// Create a ByteString from a String
ByteString("hello")
ByteString.fromString("hello")
// Create a ByteString from an Array[Byte]
ByteString(arr)
ByteString.fromArray(arr)

Java:

// Get the empty ByteString (this instance is cached)
ByteString.empty();
// Create a ByteString from a String
ByteString.fromString("hello");
// Create a ByteString from an Array[Byte]
ByteString.fromArray(arr);

*.OutsSource に移行する

Playでは、元の WebSocket.Out クラス、 Chunks.Out クラス、 EventSource.Out クラスではなく、 Source を使用してイベントを生成します。 これらのクラスは使用が簡単でしたが、柔軟性がなく、back pressure を適切に実装しませんでした。

*.Out クラスは、ストリームを生成するすべての Source で置き換えることができます。 Source を作成する方法はたくさんあります (Java/Scala)。

*.Out を単純なオブジェクトに置き換えて、バック・プレッシャーを心配することなく、メッセージを書いたり閉じることができたら、 Source.actorRef メソッドを使うことができます:

Source<ByteString, ?> source = Source.<ByteString>actorRef(256, OverflowStrategy.dropNew())
  .mapMaterializedValue(sourceActor -> {
    sourceActor.tell(ByteString.fromString("hello"), null);
    sourceActor.tell(ByteString.fromString("world"), null);
    sourceActor.tell(new Status.Success(NotUsed.getInstance()), null);
    return null;
  });

Scala:

val source = Source.actorRef[ByteString](256, OverflowStrategy.dropNew).mapMaterializedValue { sourceActor =>
  sourceActor ! ByteString("hello")
  sourceActor ! ByteString("world")
  sourceActor ! Status.Success(()) // close the source
}

EnumeratorSource に移行する

Playは多くの場所で Enumerator を使用して値のストリームを生成します。

ステップ1: 移行APIを使用する(利用可能な場合)

Results.chunked または Results.feed を使用する場合は、引き続き既存のメソッドを使用できます。 これらのメソッドは廃止されました。したがって、とにかくコードを変更したい場合があります。

ステップ2: アダプタを使用して EnumeratorSource に変換する

既存の EnumeratorStreams.enumeratorToPublisher を使用してリアクティブストリーム Publisher に変換した後、 Source.fromPublisher を使用してパブリッシャをソースに変換することで、既存の列挙子をソースに変換できます。

val enumerator: Enumerator[T] = ...
val source = Source.fromPublisher(Streams.enumeratorToPublisher(enumerator))

ステップ3: (オプション)ソースに書き直す

列挙子ファクトリメソッドの一般的なマッピングの一覧を次に示します。

Iteratees Akka Streams Notes
Enumerator.apply(a) Source.single(a)
Enumerator.apply(a, b) Source.apply(List(a, b)))
Enumerator.enumerate(seq) Source.apply(seq) seq must be immutable
Enumerator.repeat Source.repeat 繰り返し要素は、Akkaストリームで毎回評価されません
Enumerator.empty Source.empty
Enumerator.unfold Source.unfold
Enumerator.generateM Source.unfoldAsync
Enumerator.fromStream StreamConverters.fromInputStream
Enumerator.fromFile StreamConverters.fromInputStream java.io.FileのためのInputStreamを作成しなければなりません。

IterateeSinks と Accumulators に移行する

ステップ1: アダプタを使用して変換する

既存の IterateeStreams.iterateeToSubscriber を使ってリアクティブストリーム Subscriber に変換してから Sink に変換し、 Sink.fromSubscriber を使ってシンクに変換することができます。例えば:

val iteratee: Iteratee[T, U] = ...
val (subscriber, resultIteratee) = Streams.iterateeToSubscriber(iteratee)
val sink = Sink.fromSubscriber(subscriber)

Accumulator を返す必要がある場合は、代わりに Streams.iterateeToAccumulator が使えます。

ステップ2: (オプション)Sink に書き直す

iterateeファクトリメソッドの一般的なマッピングのリストを次に示します。

Iteratees Akka Streams Notes
Iteratee.fold Sink.fold
Iteratee.head Sink.headOption
Iteratee.getChunks Sink.seq
Iteratee.foreach Sink.foreach
Iteratee.ignore Sink.ignore
Done Sink.cancelled マテリアライズされた値は、結果を生成するためにマップすることができます。アキュムレータを使用する場合は、代わりに Accumulator.done を使用できます。

EnumerateesProcessor への移行

ステップ1: アダプタを使用して変換する

Flow.fromProcessor を使用して、既存の EnumerateeFlow に変換し、その後、 Flow.fromProcessor を使用して ProcessorFlow に変換できます。たとえば、次のようになります。

val enumeratee: Enumeratee[A, B] = ...
val flow = Flow.fromProcessor(() => Streams.enumerateeToProcessor(enumeratee))

ステップ2 : (オプション) Flow への書き換え

列挙型ファクトリメソッドの一般的なマッピングのリストを次に示します。

Iteratees Akka Streams Notes
Enumeratee.map Flow.map
Enumeratee.mapM Flow.mapAsync Akka Streamsの並列性、つまり一度に並列にマップされる要素の数を指定する必要があります。
Enumeratee.mapConcat Flow.mapConcat
Enumeratee.filter Flow.filter
Enumeratee.take Flow.take
Enumeratee.takeWhile Flow.takeWhile
Enumeratee.drop Flow.drop
Enumeratee.dropWhile Flow.dropWhile
Enumeratee.collect Flow.collect

Apache License 2.0

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3