Soumettre la recherche
Mettre en ligne
Writing Spring WebFlux more esay with kotlin
•
Télécharger en tant que PPTX, PDF
•
1 j'aime
•
1,566 vues
賢太郎 前多
Suivre
JJUG CCC 2018 Fall Lightning Talk
Lire moins
Lire la suite
Logiciels
Signaler
Partager
Signaler
Partager
1 sur 21
Télécharger maintenant
Recommandé
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
Yoshifumi Kawai
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
Kohei Tokunaga
Linuxにて複数のコマンドを並列実行(同時実行数の制限付き)
Linuxにて複数のコマンドを並列実行(同時実行数の制限付き)
Hiro H.
大規模分散システムの現在 -- Twitter
大規模分散システムの現在 -- Twitter
maruyama097
ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計
Yoshinori Matsunobu
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
Akihiro Suda
MagicOnion~C#でゲームサーバを開発しよう~
MagicOnion~C#でゲームサーバを開発しよう~
torisoup
ソーシャルゲーム案件におけるDB分割のPHP実装
ソーシャルゲーム案件におけるDB分割のPHP実装
infinite_loop
Recommandé
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
Yoshifumi Kawai
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
Kohei Tokunaga
Linuxにて複数のコマンドを並列実行(同時実行数の制限付き)
Linuxにて複数のコマンドを並列実行(同時実行数の制限付き)
Hiro H.
大規模分散システムの現在 -- Twitter
大規模分散システムの現在 -- Twitter
maruyama097
ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計
Yoshinori Matsunobu
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
Akihiro Suda
MagicOnion~C#でゲームサーバを開発しよう~
MagicOnion~C#でゲームサーバを開発しよう~
torisoup
ソーシャルゲーム案件におけるDB分割のPHP実装
ソーシャルゲーム案件におけるDB分割のPHP実装
infinite_loop
【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things
UnityTechnologiesJapan002
Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編
Masahito Zembutsu
それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?
Yoshitaka Kawashima
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
Yoshifumi Kawai
リアルタイムサーバー 〜Erlang/OTPで作るPubSubサーバー〜
リアルタイムサーバー 〜Erlang/OTPで作るPubSubサーバー〜
Yugo Shimizu
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
NTT DATA Technology & Innovation
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
Atsushi Nakamura
WebSocket / WebRTCの技術紹介
WebSocket / WebRTCの技術紹介
Yasuhiro Mawarimichi
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるな
Kentaro Matsui
MagicOnion入門
MagicOnion入門
torisoup
シリコンバレーの「何が」凄いのか
シリコンバレーの「何が」凄いのか
Atsushi Nakada
Riverpodでテストを書こう
Riverpodでテストを書こう
Shinnosuke Tokuda
Using or not using magic onion
Using or not using magic onion
Goichi Shinohara
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
Yoshifumi Kawai
Nginx lua
Nginx lua
Moriyoshi Koizumi
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
Takuto Wada
例外設計における大罪
例外設計における大罪
Takuto Wada
ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割
ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割
Recruit Lifestyle Co., Ltd.
TLS, HTTP/2演習
TLS, HTTP/2演習
shigeki_ohtsu
エンジニアから飛んでくるマサカリを受け止める心得
エンジニアから飛んでくるマサカリを受け止める心得
Reimi Kuramochi Chiba
Contenu connexe
Tendances
【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things
UnityTechnologiesJapan002
Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編
Masahito Zembutsu
それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?
Yoshitaka Kawashima
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
Yoshifumi Kawai
リアルタイムサーバー 〜Erlang/OTPで作るPubSubサーバー〜
リアルタイムサーバー 〜Erlang/OTPで作るPubSubサーバー〜
Yugo Shimizu
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
NTT DATA Technology & Innovation
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
Atsushi Nakamura
WebSocket / WebRTCの技術紹介
WebSocket / WebRTCの技術紹介
Yasuhiro Mawarimichi
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるな
Kentaro Matsui
MagicOnion入門
MagicOnion入門
torisoup
シリコンバレーの「何が」凄いのか
シリコンバレーの「何が」凄いのか
Atsushi Nakada
Riverpodでテストを書こう
Riverpodでテストを書こう
Shinnosuke Tokuda
Using or not using magic onion
Using or not using magic onion
Goichi Shinohara
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
Yoshifumi Kawai
Nginx lua
Nginx lua
Moriyoshi Koizumi
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
Takuto Wada
例外設計における大罪
例外設計における大罪
Takuto Wada
ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割
ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割
Recruit Lifestyle Co., Ltd.
TLS, HTTP/2演習
TLS, HTTP/2演習
shigeki_ohtsu
エンジニアから飛んでくるマサカリを受け止める心得
エンジニアから飛んでくるマサカリを受け止める心得
Reimi Kuramochi Chiba
Tendances
(20)
【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things
Dockerfile を書くためのベストプラクティス解説編
Dockerfile を書くためのベストプラクティス解説編
それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
「黒騎士と白の魔王」gRPCによるHTTP/2 - API, Streamingの実践
リアルタイムサーバー 〜Erlang/OTPで作るPubSubサーバー〜
リアルタイムサーバー 〜Erlang/OTPで作るPubSubサーバー〜
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
WebSocket / WebRTCの技術紹介
WebSocket / WebRTCの技術紹介
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるな
MagicOnion入門
MagicOnion入門
シリコンバレーの「何が」凄いのか
シリコンバレーの「何が」凄いのか
Riverpodでテストを書こう
Riverpodでテストを書こう
Using or not using magic onion
Using or not using magic onion
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
Nginx lua
Nginx lua
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
例外設計における大罪
例外設計における大罪
ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割
ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割
TLS, HTTP/2演習
TLS, HTTP/2演習
エンジニアから飛んでくるマサカリを受け止める心得
エンジニアから飛んでくるマサカリを受け止める心得
Writing Spring WebFlux more esay with kotlin
1.
Spring WebFluxを 簡単に書きたい 前多(twitter @kencharos) JJUG
CCC 2018 Fall LT
2.
About Me • 設計と実装してる人 •
Java ときどき C# • 最近 • 「GraalVM の native image を使って Java で爆速 Lambda の夢を見る」 • https://qiita.com/kencharos/items/69e43965515f368bc4a3
3.
WebFlux の使いどころ • 複数の非同期処理のフローを簡単に記述できる •
例えば 3つの WebAPI 呼び出しを順番に呼び出 したり、一部を並行(同時)にしたり、、 “hello” “world” “!!!" “hello” “world” “!!!” //WebAPI 呼び出しの例 public Mono<String> callApi() { return WebClient.create("http://xxxxx/hello") .get().retrieve().bodyToMono(String.class); }
4.
APIを逐次実行にする例 • flatMap で3つのMonoを順次実行 @GetMapping("/java/rx_seq") public
Mono<String> Seq() { // 逐次実行 Mono<String> hello = helloApi.callApi(); Mono<String> world = worldApi.callApi(); Mono<String> exclamation = exclamationApi.callApi(); return hello .flatMap(h -> world .flatMap(w -> exclamation .map(e -> h + w + e))); }
5.
APIの一部を並行にする例 • Zip で2つのMonoを待ち合わせして、その後 flatMap @GetMapping("/java/rx_seq") public
Mono<String> Par() { // 一部並列実行 Mono<String> hello = helloApi.callApi(); Mono<String> world = worldApi.callApi(); Mono<String> exclamation = exclamationApi.callApi(); return Mono.zip(hello, world) .flatMap(hw -> exclamation .map(e -> hw.getT1() + hw.getT2() + e)); }
6.
本当に簡単? • スレッドとかブロッキングとかを考えなくてい いので楽 • @Async
とか使わなくていいので楽 • 非同期処理の待ち合わせも楽 • とはいえ、従来のプログラムの書き方とは結構 違う • flatMap がネストしだすと少々見づらい • もっと楽にできないか??
7.
Kotlin のコルーチンを使う • コルーチンは処理を途中で止めたり再開したり する機能 •
Java だと Project Loom の Fiberで入るかも? • コルーチンはKotlin1.3 から標準化 • Spring5 から Kotlin 正式対応 • Reactor のコルーチン対応ライブラリ kotlinx-coroutines-reactor がある
8.
コルーチンで逐次処理の例 • mono スコープと
awaitXxx を使うと 複数のMonoを一つに結合できる @GetMapping("seq") fun seqWithCoroutine():Mono<String> = GlobalScope.mono { // awaitFirst で、 Monoを コルーチンに val hello: String = helloApi.callApi().awaitFirst() val world: String = worldApi.callApi().awaitFirst() val exclamation: String = exclamationApi.callApi().awaitFirst() "$hello $world $exclamation" } monoスコープ で囲む MonoにawaitFirstでコルーチン化。 Monoの中の結果のString を取得で きる この値(3 APIの呼び出し結果の連結)が 最終的な戻り値になる
9.
コルーチンで並行化の例 • asyncで一部を非同期実行できる @GetMapping("par") fun parWithCoroutine():Mono<String>
= GlobalScope.mono { // start helloApi and worldApi tasks in asynchronous. val helloDeferred = async { helloApi.callApi().awaitFirst() } val worldDeferred = async { worldApi.callApi().awaitFirst() } // join 2 tasks val hello: String = helloDeferred.await() val world: String = worldDeferred.await() val exclamation = exclamationApi.callApi().awaitFirst() "$hello $world $exclamation" } async スコープ で非同期処理 開始 非同期処理の 結果は await で取得
10.
コルーチンの Pros/Cons • Pros •
同期処理っぽく書ける(flatMapが消えた) • 通常の kotlinの制御構文が使える(if, for, try/catch) • JavaScript/C# の async/await に近い感じ • async でカジュアルに一部を非同期処理にできる • Cons • awaitの呼び出しごとに Rxの subscribe が実行されて いる • Rx の文脈をコルーチンの非同期処理に置き換えてしまう • 他には?
11.
Arrowライブラリを使う • https://arrow-kt.io/ • Scala
の関数型ライブラリ Scalaz, Cats のような 関数型プログラミングの機能(モナドとか)を Kotlinに持ち込む • Reactor 用の拡張を使うと、 Mono, Flux を MonoK, FluxK に変換して モナドにできる
12.
Arrowで逐次処理の例 • 大体の記述はコルーチンと似ている • bindingスコープ(モナド記法),
k(), bind() を使う @GetMapping("monad_seq") fun seqWithMonad():Mono<String> = MonoK.monad().binding { // K() is buidler from Mono to MonoK. MonoK is Monad of Mono in Arrow. // bind() is flatMap as Coroutine. val hello: String = helloApi.callApi().k().bind() val world: String = worldApi.callApi().k().bind() val exclamation: String = exclamationApi.callApi().k().bind() "$hello $world $exclamation" }.value() K()でMonoを MonoKに value()で MonoKをMono に戻す 最終的な 戻り値 bind() でMono の中の String を取得できる
13.
Arrow で並行処理 • Mono.zip
で待ち合わせしたMonoをbindする • Arrowだけで 並行化する方法を調査中 @GetMapping(“monad_par”) fun parWithMonad():Mono<String> = MonoK.monad().binding { val hMono = helloApi.callApi() val wMono = worldApi.callApi() // 並列化は Mono zip を使うしかないっぽい val helloWorld = Mono.zip(hMono, wMono).map { it.t1 + it.t2 }.k().bind() val exclamation = exclamationApi.callApi().k().bind() "$helloWorld $exclamation" }.value()
14.
ArrowのPros/Cons • Pros • bindを使って、同期処理っぽく書ける •
bind 呼び出しは flatMap の呼び出しに置き換わるの で Rx の文脈は保たれる • Arrowの他の機能との統合(後述) • モナド完全に理解した • Cons • モナド全然わからん • 関数型プログラミングの理解が必須 • Mono.zip の代替手段が(今のところ)なさそう • アプリカティブなだけの Monoがなさそう
15.
ここまでまとめ • Kotlinなら WebFlux
が使いやすくなるかもよ • バックプレッシャー周りは継続調査
16.
(おまけ) Arrow の
Either • Either は成功か失敗かのどちらかの表現 • 例外の代わりに使うことが多い • ArrowのEither はモナドなので合成可能 fun aToI(s:String):Either<NumberFormatException, Int> { if (s.matches("^[0-9]+$".toRegex())) { return Either.right(Integer.parseInt(s)) } else { return Either.left(NumberFormatException("invalid string")) } } val result = aToI("123") when(result) { is Either.Right -> print("OK " + result.b) is Either.Left -> print("NG" + result.a.message) } Right(成功) Left(失敗)
17.
MonoKとEitherが組み合わさると • 非同期処理の結果に Either
を使って失敗の可能 性を表現したい場合、Mono(K)とEither を組み 合わせた型ができる fun callApiOrError(name:String):MonoK<Either<Throwable, String>> {///}
18.
モナドのネストは見づらい • MonoKのbindでEither が取れてしまう •
EitherからStringを取るとモナドがネストする val resEither = MonoK.monad().binding { val helloEither:Either<Throwable, String> = helloApi.callApiOrError(query).bind() val worldEither = worldApi.callApiOrError(query).bind() val exclamationEither = exclamationApi.callApiOrError(query).bind() // モナドにモナドがダブってしまう Either.monadError<Throwable>().binding { val hello:String = helloEither.bind() val world:String = worldEither.bind() val exclamation:String = exclamationEither.bind() "$hello $world $exclamation" }.fix() }.value()
19.
EitherT で MonoK<Either>
を合体する • EitherT (モナドトランスフォーマー)を使う と、モナドのネストが消え、従来通りにかける • bind でMono, Eitherの両方を一発ではがす • bindがどこかで失敗(=Either.Leftの発生)するとその 場で評価を停止し、MonoK(Either.Left)を返す • 全て成功した場合は、MonoK(Either.Right)を返す val result = EitherT.monad<ForMonoK, Throwable>(MonoK.monad()).binding { val hello:String = EitherT(helloApi.callApiOrError(query)).bind() val world:String = EitherT(worldApi.callApiOrError(query)).bind() val exclamation = EitherT(exclamationApi.callApiOrError(query)).bind() "$hello $world $exclamation" }
20.
最終的な変換処理は必要 • 最終的に Mono<Either<T>>
をちゃんと変換する コードは必要 • 機械的に書ける内容なので、 Mono<Either<T>> をコ ントローラの戻り値にして、Spring 側でハンドリン グするようにできるはず val res:Mono<Either<Throwable, String>> = result.fix().value().value() return res.map { when(it){ is Either.Right -> ResponseEntity.ok().body(it.b) is Either.Left -> ResponseEntity.badRequest().body(it.a.message) } }
21.
おしまい • Kotlin +
Arrow で Functional Reactive Spring の夢 が見よう! • ソース • https://github.com/kencharos/webflux-coroutine- arrow-sample • Arrow の Either についてはアドカレ書いてます • https://qiita.com/kencharos/items/6fd0a9e92363b08c0340 • 「例外だけに頼らない Kotlinのエラーハンドリング」
Notes de l'éditeur
Spring Fluxの使いどころはMonoやFluxで表す非同期処理が複数ある場合、そのつなぎ方逐次や同時など色々書けることだと思います。
3つの非同期処理を順番に呼び出す場合、flatMapでつなげます。
一部を並列化したい場合は、zipで二つのMonoをくっつけます
Reactorならスレッドとかasyncとか使わなくていいので、楽だとは思いますが、flatMap慣れないとつらいですよね。もっと簡単に書けないでしょうか
で、唐突にKotlinが出てきます。Kotlinのコルーチンは処理の停止・再開を行う機能で非同期処理の代わりに使えます。 Reactor 拡張があるのでこれを使ってみます。
Monoを順番に呼び出す場合は、スコープのなかでawait を使います。Await を使うとMonoの中にあるString が取れるのでそれを連結した値が、最終的なMonoになります。
並列化したい場所、並列にしたい部分を async で囲んで、await で取得すればOKです。
コルーチン使うと、JSのasyc.await みたいな同期的な書き方ができます。Try-catchもできます。 一方で、awaitするごとに Rxのsubscribe 読んでるみたいなので、Rxのやり方を壊してる感じがします。他の方法も見てみます。
Kotlinには Arrow という関数型のライブラリがあります。いわゆるモナドというやつです。
コルーチンみたいに、スコープの中で、bind を使うと Monoの中のStringが取れます。またbindは flatMap と同じです。
並列にしたい場合は、 Monoのzipの後に bind しないといけないので、そこは同じです。
Arrow の bindは、flatMapと同じなので、同期処理みたいに書きつつも、Rxとやっていることが同じになります。 モナドすごいと同時に、全然わからんみたいなになりがちなので、関数型プログラムの知識がある程度いります。聞いて下さい。
ここで一旦まとめると、 Kotlinなら WebFlux楽できそう。バックプレッシャーとかは継続して調査という感じです。
時間が余ってれば、 もう少しArrowの話を。関数型で例外投げるみたいなことをした場合、 Eitherという型を使います。 Rightが成功、Leftが失敗でどちらかだけを持つというデータです。
失敗するかもしれない、非同期処理の結果を示したくなると、こんな感じで、 MonoとEitherが組み合わさります。
で、これをスコープで合成しようとすると、 bindして取れる値が Either なのでもう一度 スコープ作ってbindしないと Stringが取れないわけです。
ここで登場するのが、モナドトランスフォーマーという機能で、 EitherTというトランスフォーマーで、Mono,Eitherを囲んで bind すると、両方を一気にはがして Stringが取れます。 途中の Eitherが失敗したら、その場でエラーになってくれます。大体今までと同じように書けます。
ただ、最終的に Mono,Either の適切は処理はいるので、そこはフレームワークの内部でうまくやるようにすると、いい感じになるんじゃないかと思ってます。 上みたいに、成功ならOK、失敗なら badRequestにするとかね。
おしまいです。Functional reactive Spring ができそうという話でした。 スライドとソースは公開するので、気になった人はじっくり見てみてください。
Télécharger maintenant