Upgrade to Pro — share decks privately, control downloads, hide ads and more …

リアクティブシステムの鼓動(Scala/Akka)

 リアクティブシステムの鼓動(Scala/Akka)

システムの非機能要件は以前より高い要求を求められる傾向にあります。
たとえば、
– より多くのコアを使うには?
– より短い応答時間にするには?
– 限りなく0時間に近いダウンタイムにするには?
– ペタ規模のデータを扱うには?
などと考える機会が増えたと思います。
このような背景で登場したコンセプトが、”レスポンスが速い・障害に強い・負荷に応じてスケールする” 特徴を持つリアクティブシステム(リアクティブプログラミングのことではありません)です。最近注目されているので、言葉だけは耳にしたことがあるのではないでしょうか。クラウドやビッグデータ基盤の進化に合わせてアプリケーション設計の考え方も転換する時期だから注目されているのかもしれません。しかしながら、リアクティブシステムは登場してまだ間もないので、今後に備えてその鼓動を感じてもらえるセッションにしたいと思います。
そして、このリアクティブシステムの定義はリアクティブ宣言に定められていますが、そのFirst AuthorはLightbend社のCTO Jonas Bonér氏です。Lightbend社はScalaやAkkaにコミットしている会社です。ということで、紹介するコードはScala/Akka前提になります:P Scala vs Java8などの言語比較だけではなく、求められるシステム要件から言語やフレームワークの選定を考えたい方にはおすすめ。

かとじゅん

September 24, 2016
Tweet

More Decks by かとじゅん

Other Decks in Technology

Transcript

  1. ࣗݾ঺հ w ͔ͱ͡ΎΜ !KJLP  w IUUQCMPHKJLPNF w ࢓ࣄ͸$IBU8PSLࣾͰςοΫϦʔυ w

    $IBU8PSLαʔόج൫෦෼ͷ৽ن։ൃ w ઐ໳෼໺ʁ w υϝΠϯۦಈઃܭ w ϦΞΫςΟϒγεςϜ w ࠷ۙݚᮎ͍ͯ͠Δ͜ͱ w 4DBMB"LLB %%% w "OHVMBSc3FBDU  %%%
  2. 4FBTBS͔Β4DBMB΁ w ೥͔Β w 5FFEB 4%BP w 4$ISPOPT 4$POpH w

    ೥݄͔Β w ࢓ࣄͰ͸+BWBɻझຯͰ͸4DBMBɻ w ೥݄ w ๭EࣾεϚϑΥ޲͚3&45"1*αʔόΛ1MBZͰ։ൃ w ๭Eࣾνϟοτ"1*αʔόΛ'JOBHMFͰ։ൃ ϓϩτλΠϓ։ൃ  w ೥ w ๭(ࣾνϟοτ"1*αʔόΛ'JOBHMFͰ։ൃɻ w ೥ w $IBU8PSLࣾϝοηʔδϯάج൫Λ"LLBͰ։ൃɻ"LLBΛ·͡Ίʹ ࣮ફͰ࢖͍࢝Ίͨͷ͸਺ϲ݄ɻ
  3. എܠʹ͍ͯ͠ΔίϯςΩετͷมԽ w αʔό୆਺ͷมԽ w ਺े୆͔Β਺ઍίΞ΁ w Ԡ౴࣌ؒͷมԽ w ඵ͔ΒϛϦඵΦʔμʔ΁ w

    μ΢ϯλΠϜͷมԽ w ਺͔࣌ؒΒݶΓͳ࣌ؒ͘΁ w σʔλن໛ͷมԽ w ΪΨ͔Βϖλ΁
  4. ࢧ͑Δݪཧ ఏڙ͢ΔՁ஋ લఏͱͳΔखஈ ϦΞΫςΟϒએݴ w IUUQXXXSFBDUJWFNBOJGFTUPPSH w ʹެ։͞Εͨએݴɻ໊ ͕ॺ໊ɻ-JHIUCFOEࣾͷ$50 +POBT#POÉSࢯ͕'JSTU"VUIPSɻ

    w ଈԠੑ 3FTQPOTJWF  w γεςϜ͸ՄೳͳݶΓ଎΍͔ʹԠ ౴͢Δɻ w ଱ো֐ੑ 3FTJMJFOU  w γεςϜ͸ো֐ʹ௚໘ͯ͠΋ଈԠ ੑΛอͪଓ͚Δɻ ଈԠੑ ϝοηʔδۦಈ ଱ো֐ੑ ஄ྗੑ w ஄ྗੑ &MBTUJD  w γεςϜ͸ϫʔΫϩʔυ͕ม ಈͯ͠΋ଈԠੑΛอͪଓ͚Δɻ w ϝοηʔδۦಈ .FTTBHF %SJWFO  w ίϯϙʔωϯτؒΛඇಉظ ʹϝοηʔδΛૹड৴͢Δ ௨৴ελΠϧɻϝοηʔδ ύογϯάͱ΋ݴΘΕΔɻ
  5. "LLBͱ͸ w IUUQBLLBJPॳظϦϦʔε͸೥ɻ w -JHIUCFOEࣾ$50+POBT#POÉSࢯ͕࠷ॳʹ։ൃɻ w ىݯ͸&SMBOHɻ w "DUPSϞσϧ͸೥ʹ.*5ͷ$BSM)FXJUUࢯ͕ߟҊ ͕ͨ͠ɺ࣮༻Ͱ͸&SMBOHΑͬͯ༗໊ʹͳͬͨɻ

    w ಛ௃ w ϦΞΫςΟϒએݴͷίϯηϓτΛαϙʔτ͍ͯ͠Δ w ࠾༻ࣄྫ w ιʔγϟϧϝσΟΞɺσʔλղੳɺϔϧεέΞɺ౤ ࢿ෼໺ ϚʔνϟϯτɾόϯΩϯά ɺΪϟϯϒϧ ܥʜɻ
  6. ͳͥ"LLBͳͷ͔  w $16ةػ w γϯάϧίΞةػ ೥ࠒ͔ΒϚϧνίΞొ৔  w ϚϧνίΞ͸୯ҰίΞ͕௿଎ʹͳΔ܏޲ʹ͋ΔͨΊɺΞϓϦ

    έʔγϣϯͷฒߦ౓͕௿͍ͱύϑΥʔϚϯε͕௿Լ͢Δͱ͍ ͏ϦεΫ͕͋Δ ϚϧνίΞةػ ɻ͔͠͠ɺεϨουϓϩά ϥϛϯά͸ɺσουϩοΫ΍ϨʔείϯσΟγϣϯɺՄࢹੑ ͷ໰୊ͳͲͰඇৗʹ೉͍͠ͱ͍͏໰୊͕͋Δɻ w $,໰୊ w ૿͑ଓ͚ΔΫϥΠΞϯτΛͲͷΑ͏ʹॲཧ͢Δ͔ͷ໰୊ɻ໰ ୊ʹͳΔͷ͸ϒϩοΩϯά*0 /HOJY ʙ  /PEFKT ʙ ͸ϊϯϒϩοΩϯά*0ͱΠϕϯτϧʔϓͰ ղܾͨ͠
  7. ͳͥ"LLBͳͷ͔  w ϚϧνίΞةػΛλʔήοτʹͨ͠ݴޠͷొ৔ w &SMBOH 4DBMB ʜ w ෆมੑ΍ܰྔϓϩηεͳͲ

    w &SMBOHͷ఻આ w ೥&SJDTTPO͕ΞΫλʔϞσϧΛϕʔεʹͨ͠&SMBOHΛ։ ൃɻి࿩ަ׵ػͰ OJOFOJOFT࿦ཧతʹ͸ ೥ؒͷՔಇͰඵͷఀࢭ࣌ؒ ɻ೥8IBU"QQ͕୆ͷ αʔόͰສΫϥΠΞϯτΛࡹ͘ɻ w "LLBͷొ৔ w ೥"LLBϦϦʔεɻϝοηʔδۦಈ ϊϯϒϩοΩϯ ά*0Ͱ$,໰୊Λղܾɻ೥ͷهࣄͰ͸&SMBOHͷഒͷ εϧʔϓοτΛൃشͨ͠ͱ͍͏ࣄྫ΋͋Δɻ
  8. "LLBͷओͳϓϩμΫτ  w BLLBBDUPS w ෼ࢄͱฒߦΛ࣮ݱ͢ΔͨΊͷΞΫλʔϞσϧΛఏڙ͢Δɻ؆୯ͳ"1* ͰεϨου؅ཧ΍ϩοΫͷऔΓѻ͍Λܰݮɻ w BLLBSFNPUF w

    ϦϞʔτ্ͷϊʔυͰՔಇ͢ΔΞΫλʔʹϝοηʔδύογϯά͢Δ ͨΊͷϓϩμΫτɻ w BLLBDMVTUFS w ଱ো֐ੑͷ͋Δ෼ࢄܕ11ϕʔεΫϥελΛߏங͢ΔͨΊͷϓϩμΫ τɻBLLBDMVTUFSTIBSEJOHΛ࢖͏ͱΫϥελʔ্ͷಛఆͷϊʔυʹΞ ΫλʔΛγϟʔσΟϯάͰ͖Δɻ w BLLBIUUQ FYQFSJNFOUBM  w )551Λܦ༝ͯ͠"DUPSΛެ։ͨ͠Γɺ"DUPSϕʔεͷ)551ΫϥΠΞϯ ταʔϏεΛར༻͢ΔͨΊͷϓϩμΫτɻ1MBZ͔Β࣮ݧతʹ૊Έ ࠐ·Ε͍ͯΔɻࠓޙ͸/FUUZΛࣺͯΔ͜ͱʹͳΔɻ
  9. "LLBͷओͳϓϩμΫτ  w BLLBQFSTJTUFODF w εςʔτϑϧΞΫλʔͷ಺෦ঢ়ଶΛӬଓԽ͢ΔػೳɻΞΫλʔͷॳظ Խ࣌΍ྫ֎ʹΑΔ࠶ىಈ࣌ɺ+7.ͷΫϥογϡ࣌ʹҎલͷঢ়ଶΛ෮ݩ ͢Δ͜ͱ͕Ͱ͖Δɻ w BLLBQFSTJTUFODFRVFSZ

    w ඇಉظετϦʔϜϕʔεͷΫΤϦ*'ʹΑͬͯఏڙ͞ΕΔΫΤϦʔί ϯϙʔωϯτɻ w BLLBTUSFBN w ΞΫλʔΛ࿈݁ͤͯ͞ඇಉظετϦʔϜॲཧΛ͢ΔͨΊͷ1JQFBOE 'JMUFSΛ࡞Δ͜ͱ͕Ͱ͖Δ͕ɺ҆ఆͨ͠ετϦʔϛϯάॲཧΛ͢Δʹ ͸ɺΤϥʔϋϯυϦϯάΛߦͬͨΓɺ͋Δϓϩηε্ͷόοϑΝ΍ ϝʔϧϘοΫε͕Φʔόʔϑϩʔ͠ͳ͍Α͏ʹ͢Δ CBDLQSFTTVSF ඞཁ͕͋Δɻ੩తܕͳཁૉΛѻ͏ετϦʔϜͰΞΫλʔ͸഑ઢϛεΛ ๷ࢭ͢Δ੩తܕ෇͚Λอূ͢Δํ๏͕ͳ͍ɻBLLBTUSFBN͸͜ΕΒͷ ໰୊Λղܾ͢Δɻ
  10. ':*଱ো֐ੑͷલʹ·ͣzιϑτ΢ΣΞͷࡂ͍Λද͢༻ޠz w ޡࠩɾޡΓ FSSPS  w ܭࢉɼ؍ଌए͘͠͸ଌఆ͞Εͨ஋ຢ͸ঢ়ଶͱɼ ਅͷɼࢦఆ͞Εͨए͘͠͸ཧ࿦తʹਖ਼͍͠஋ ຢ͸ঢ়ଶͱͷؒͷ૬ҧ +*49

     w ܽؕ EFGFDU όάΛؚΉ֓೦  w ҙਤͨ͠ৼΔ෣͍͔ΒγεςϜ͕ҳΕͯ͠· ͏ݪҼͱͳΔιϑτ΢ΣΞγεςϜͷಛੑͰ ͋Δ ΦϒδΣΫτࢦ޲ೖ໳ୈ̎൛ݪଇɾί ϯηϓτܖ໿ϓϩάϥϛϯά  w ো֐ GBVMU ˠ"LLB͸GBVMUUPMFSBODF w ཁٻ͞ΕͨػೳΛ਱ߦ͢Δػೳ୯Ґͷೳྗͷɼ ॖୀຢ͸૕ࣦΛҾ͖ى͜͢ɼҟৗͳঢ়ଶ +*4 9  w ނো GBJMVSF  w ཁٻ͞ΕͨػೳΛ਱ߦ͢Δɼػೳ୯Ґͷ ೳྗ͕ͳ͘ͳΔ͜ͱ +*49 Ұൠతͳ࿈࠯ϑϩʔ ނো ޡࠩɾޡΓ ো֐ ܽؕ ނো
  11. ώΤϥϧΩʔ ଱ো֐ੑ 3FTJMJFOU w ͦΕ͸Ұ౓΋ো֐Λى͜͞ͳ ͍ɺ׬શͳΞϓϦέʔγϣϯ ιϑτ΢ΣΞΛ࣮૷͢Δ͜ͱ Ͱ͸ͳ͍ɻো֐͔Βճ෮͢Δ ͨΊͷೳྗΛσβΠϯ͢Δɻ w

    ϦΞΫςΟϒγεςϜͰ͸ɺ ԼҐͷίϯϙʔωϯτ্ͷεʔ ύόΠβͱର࿩͢Δ͜ͱͰো ֐ʹඋ͑ΔɻεʔύʔόΠβ ͸ɺ؂ಜԼʹ͋Δίϯϙʔω ϯτͷো֐ʹ൓Ԡ͢ΔػձΛ ༩͑ΒΕΔɻ "DUPS 4VQFSWJTPS ো֐ͷൃੜ "DUPS ؂ಜऀͷࢦࣔ ܖ໿ҧ൓࣌͸ΤϥʔΛฦ͢ SFR SFT
  12. ଱ো֐ੑ 3FTJMJFOU w ো֐ൃੜ࣌ʹɺԼҐίϯϙʔ ωϯτΛఀࢭͨ͠Γɺ࠶ىಈ ͨ͠Γɺແࢹͯ͠ܧଓͨ͠Γ Ͱ͖Δɻ·ͨɺ͞Βʹ্Ґͷ εʔύόΠβνΣΠϯʹো֐ ௨஌ΛΤεΧϨʔτ͢Δ͜ͱ ΋Ͱ͖Δɻ

    w ͜ͷΞϓϩʔνͰো֐͕ൃੜ ͨ͠ྖҬΛ෼཭͠ɺଞͷؔ܎ ͠ͳ͍ଟ͘ͷྖҬΛอޢ͢Δ ͜ͱ͕Ͱ͖Δɻ͜ΕΒΛশ͠ ͯࣗݾճ෮ྗͱ͍͏ɻ "DUPS 4VQFSWJTPS ো֐ൃੜ ྫ֎௨஌ 4VQFSWJTPS ྫ֎ͷΤεΧϨʔτ ఀࢭ ࠶ىಈ ܧଓ ఀࢭ ࠶ىಈ ܧଓ "DUPS "DUPS "DUPS "DUPS "DUPS ࠶ىಈ࣌͸ೖସ
  13. ஄ྗੑ &MBTUJD w εέʔϥϏϦςΟʹ͸ɺਨ௚ͱਫ ฏ͕͋ΔɻͲͪΒ͔Ұํ΋͘͠ ͸྆ํಉ࣌ʹ࢖͏͜ͱ͕Ͱ͖Δɻ ஄ྗੑͱ͸ཁٻʹԠͨ͡εέʔ ϦϯάઓུɻΦϑϐʔΫ࣌͸ແବ ʹϦιʔεΛར༻͠ͳ͍ͳͲɻ w

    ϝοηʔδۦಈʹΑͬͯɺίϯ ϙʔωϯτ͸ඞཁʹԠͯ͡ಁա తʹϩʔΧϧϊʔυ΋ϦϞʔτ ϊʔυ΋ར༻Ͱ͖ΔɻҐஔಁա ੑͷ͋ΔίϯϙʔωϯτΛར༻ Ͱ͖Δɻίϯϙʔωϯτͷϝο ηʔδۦಈͱҐஔಁաੑͷ྆ํ Ͱ஄ྗੑΛ࣮ݱ͢Δɻ /PEF DPSF UISFBE DPSF UISFBE DPSF UISFBE DPSF UISFBE "DUPS "DUPS "DUPS "DUPS /PEF "DUPS /PEF "DUPS /PEF "DUPS .FTTBHF *UXJMMCFTFOUBNFTTBHFCZVTJOH"DUPS3FG 4DBMJOHVQ 4DBMJOHPVU 4DBMJOHPVU 4DBMJOHPVU 4DBMJOHPVU 4DBMJOHPVU
  14. ϝοηʔδۦಈ .FTTBHF%SJWFO w ϝοηʔδΛड৴ͯ͠ॳΊͯɺར༻ՄೳͳεϨουΛ࢖ͬͯ൓Ԡ͢Δɻϝοηʔδʹ൓ Ԡ͠ͳ͍ίϯϙʔωϯτ͸وॏͳ$16ࢿݯΛফඅ͠ͳ͍ɻ w ϝοηʔδʹ൓Ԡ͢Δ͔Ͳ͏͔͸ίϯϙʔωϯτ͕બ୒Ͱ͖ɺى͖ಘΔϝοηʔδʹඋ ͑Δ͜ͱ͕Ͱ͖Δɻ͜ΕʹΑͬͯɺૹ৴ଆͱड৴ଆͷίϯϙʔωϯτ͸ɺΠϯλʔϑΣ Πεͱ͔࣌ؒΒ෼཭͞ΕΔ γϟʔσΟϯά

    ӬଓԽΞΫλʔͰ͸෺ཧతۭؒ΋෼཭͞Ε Δ ɻ w ϝοηʔδ͸ඇಉظʹૹ৴͞Είϯϙʔωϯτ͸Ұ౓ʹܾ·ͬͨ୯ҐͷϝοηʔδΛॲ ཧ͢Δɻ$16Λසൟʹফඅ͢ΔϙʔϦϯάͱϒϩοΩϯάΛ࠾༻ͤͣɺߴεϧʔϓοτ ʹϑΥʔΧε͢ΔͨΊʹ$16Λղ์͢ΔɻඞཁʹԠͨ͡൓Ԡ͕௿ϨΠςϯγʔΛಋ͘ɻ ඞཁʹԠͯ͡όοΫϓϨογϟʹΑΔϑϩʔ੍ޚ΋Մೳ "DUPS "DUPS DMBTT5PEP"HHSFHBUFFYUFOET"DUPS\ PWFSSJEFEFGSFDFJWF3FDFJWF\
 ࠷ޙʹॲཧͨ͠ίϚϯυ*%ΑΓ େ͖͘ͳ͍ͱॲཧ͠ͳ͍ ܖ໿ͷදݱ  DBTFSFR$SFBUF5PEPJGDNEJEMBTU*E Ϩεϙϯε΋ඇಉظʹฦ͞ΕΔ ੒ޭ $SFBUF5PEP4VDDFFEFE Λฦ͢ TFOEFS DSFBUF5PEP SFR  DBTFDNE$SFBUF5PEPJGDNEJEMBTU*E TFOEFS $SFBUF5PEP&SSPS ʜ ΤϥʔΛฦ͢ ^ PWFSSJEFEFGSFDFJWF3FDFJWF\
 DBTFSFRʜ UPEP"HHSFHBUF$SFBUF5PEP ʜ  'JSFBOE'PSHFU ൃՐͨ͠Β͙͢ʹ๨ΕΔ DBTFSFT$SFBUF5PEP4VDDFFEFE Ϩεϙϯε͕͖ͨΒ൓Ԡ͢Δ
 ^
  15. BLLBBDUPSͷྫ class MyActor extends Actor {
 val log = Logging(context.system,

    this)
 
 def receive = {
 case n: Int => log.info("received {}", n)
 case msg: String => sender() ! "***" + msg + "***"
 case _ => log.info("received unknown message")
 }
 }
 
 implicit val system = ActorSystem()
 
 val props1 = Props[MyActor]
 
 val actorRef = system.actorOf(props1)
 
 actorRef ! 1
 
 val future = (actorRef ? "HelloWorld").mapTo[String]
 val result = Await.result(future, Duration.Inf)
 println(result)
 
 actorRef ! 1L 'JSFBOE'PSHFU͸౤͛ͬͺͳ͠ɻϝιο υίʔϧʹ૬౰͢Δϝοηʔδ͸ΞΫλʔ ͕ड͚ೖΕΔ͔Ͳ͏͔ΛܾΊ͍ͯΔɻ໭ Γ஋͸࣌ؒతͳ੍໿͕ͳ͍ɻϝοηʔδ ͸TFOEFSʹฦ౴Λฦ͞ͳ͍XBZͱTFOEFS ʹฦ౴Λฦ͢XBZ͕͋Δɻ
  16. 4VQFSWJTPSΛ࣮૷͢Δ class Supervisor(childProps: Props) extends Actor {
 
 override val

    supervisorStrategy = OneForOneStrategy() {
 case _: NumberFormatException => Restart
 case _: IllegalArgumentException => Stop
 case _: Exception => Escalate
 }
 
 val child = context.actorOf(childProps, "child")
 
 override def receive: Receive = {
 case msg => child forward msg
 }
 }
 4VQFSWJTPS͕ड৴ͨ͠ϝοηʔδ͸ࢠΞΫλʔʹసૹ͢Δɻ TFOEFSΛม͑ͳ͍ɻ
 ਺஋ม׵Ͱ͖ͳ͍৔߹͸3FTUBSU ෆਖ਼ͳೖྗ৚݅ͳΒ&TDBMBUF ͢ΔɺεʔύόΠβετϥςδΛ૊ΈࠐΉɻ4VQFSWJTPS͸ྫ֎ Λड͚औΔͱো֐Λִ཭͢Δɻ
  17. ࢠΞΫλʔΛ࣮૷͢Δ case class ToInt(value: String)
 case class IntValue(value: Int)
 


    class MyActor extends Actor {
 val log = Logging(context.system, this)
 
 @scala.throws[Exception](classOf[Exception])
 override def preStart(): Unit = {
 log.info("child start")
 super.preStart()
 }
 
 def receive = {
 case ToInt(v) =>
 require(v.length > 0)
 sender() ! IntValue(v.toInt)
 case _ =>
 }
 
 @scala.throws[Exception](classOf[Exception])
 override def postStop(): Unit = {
 log.info("child stop")
 super.postStop()
 }
 
 } ࢠΞΫλʔͰ͸جຊతʹྫ֎ΛϋϯυϦ ϯά͠ͳ͍ɻਖ਼ৗܥͷΈͷ࣮૷ͰΑ͍ɻ TFOEFS ͸4VQFSWJTPSͰ͸ͳ͍ΦϦδφ ϧɻ
  18. 4VQFSWJTPSܦ༝Ͱ࣮ߦ͢Δ implicit val system = ActorSystem()
 val childProps = Props[ToIntActor]


    val props = Supervisor.props(childProps)
 
 val toIntActorRef = system.actorOf(props)
 
 Seq("1", "a", "2", "").foreach{ s =>
 try {
 val future = (toIntActorRef ? ToInt(s)).mapTo[IntValue]
 val result = Await.result(future, Duration.Inf)
 println(s"value = $s, result = $result")
 } catch {
 case ex: Exception =>
 ex.printStackTrace()
 }
 } ظ଴͢Δɺظ଴͠ͳ͍ɺೖྗ஋Λ౉ͯ͠ΈΔɻ
  19. [INFO][akka://default/user/$a/child] child start 
 // 1ճ໨͸੒ޭɻ value = 1, result

    = IntValue(1) // 2ճ໨͸ࣦഊɻ࠶ىಈ͕͔͔Δɻ [ERROR][akka://default/user/$a/child] For input string: “a" java.lang.NumberFormatException: For input string: "a" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) [INFO][akka://default/user/$a/child] child stop [INFO][akka://default/user/$a/child] child start akka.pattern.AskTimeoutException: … 
 // 3ճ໨͸੒ޭ value = 2, result = IntValue(2) // 4ճ໨͸ࣦഊɻΞΫλʔ͕ఀࢭ͢Δ [ERROR][akka://default/user/$a/child] requirement failed java.lang.IllegalArgumentException: requirement failed at scala.Predef$.require(Predef.scala:212) [INFO][akka://default/user/$a/child] child stop akka.pattern.AskTimeoutException: … ࣮ߦ݁Ռ "DUPSΠϯελϯε͸࠶ىಈ͕ͨ͠"DUPS3FG͸ͦͷ· ·ར༻Մೳɻ௨ৗͷΦϒδΣΫτࢀরͰ͸ΦϒδΣΫ τάϥϑͷೖΕସ͕͑ߴίετʹͳΔ͜ͱ͕͋Δɻ
  20. ':*εʔύϏδϣϯώΤϥϧΩʔ  w εʔύόΠβͷϥΠϑλΠϜ͸ɺࢠΞΫλʔ ͕ଘࡏ͢Δؒͱಉ͡ɻ਌ʹΑͬͯ࡞ΒΕͨ ࢠΞΫλʔ͸ɺεʔύόΠβͷ؂ಜԼʹ ஔ͔ΕΔɻεʔύόΠβͷ੹೚͸͢΂ͯ ͷࢠΞΫλʔ͕ऴྃͨ࣌͠ʹऴΘΔɻ w Ϋϥογϡ͢ΔՄೳੑ͕ߴ͍ΞΫλʔ͸ɺ

    ՄೳͳݶΓώΤϥϧΩʔͷԼ૚ʹ഑ஔ͢ ΂͖ɻԼ૚Ͱى͖ͨো֐͸ɺ্Ґ·Ͱͷ ώΤϥϧΩʔ͕؅ཧɾΤεΧϨʔγϣϯ ͕Մೳɻ࠷্Ґ͕ো֐Λىͨ͜͠৔߹ ͸ɺ࠷্ҐͷΞΫλʔͷ࠶ىಈ΋͘͠͸ ΞΫλʔγεςϜͷγϟοτμ΢ϯ͕ඞཁ ʹͳΔɻ 4VQFSWJTPS 4VQFSWJTPS 4VQFSWJTPS $IJME $IJME 4VQFSWJTPS $IJME $IJME $IJME $IJME $IJME
  21. ':*εʔύϏδϣϯώΤϥϧΩʔ  w ར఺͸ɺ֤ΞΫλʔ͕૬ޓ ʹ௚઀௨৴͢Δ͜ͱɻεʔ ύόΠβ͸؂ಜۀ຿ͱΠϯ ελϯε࡞੒ͷΈɻ w ܽ఺͸ɺ࠶ىಈ͔͠࢖͑ͳ ͍͜ͱͱɺϝοηʔδ͕σο

    υϨλʔʹૹΒΕࣦͯΘΕ ͯ͠·͏͜ͱɻ਌ͷ؂ಜ͸ ϝοηʔδϑϩʔ͔Β؂ಜ Λ෼཭ͯ͠͠·͏ɻ -PH'JMF8BUIDFS 4VQFSWJTPS -PH1SPDDFTTPS 4VQFSWJTPS 3PX -PH'JMF /FX'JMF %BUBCBTF -PH1SPDDFTTPS %C8SJUFS -PH'JMF8BUIDFS %C8SJUFS 4VQFSWJTPS ώΤϥϧΩʔͷҧ͏-PH1SPDDFTTPSͷ "DUPS3FGΛಘΔͷ͸೉͍͠
  22. ':*εʔύϏδϣϯώΤϥϧΩʔ  w εʔύόΠβ͸୯ͳΔੜ੒ ΍؂ಜͰ͸ͳ͘ɺؒ઀ࢀর ͱͯ͠ɺ͢΂ͯͷϝοηʔ δΛ୯ʹಁաతʹϑΥϫʔ υ͢ΔɻεʔύόΠβ͸ࢠ Λऴྃͨ͠ΓɺଞͷΞΫλʔ ͱ͸ແؔ܎ʹ৽͍͠΋ͷΛ

    ੜΈग़ͨ͠ΓͰ͖Δɻ w ઌͷྫͱൺ΂ͯϝοηʔδ ϑϩʔͷΪϟοϓ͕ͳ͍ɻ -PH'JMF8BUIDFS4VQFSWJTPS -PH1SPDDFTTPS4VQFSWJTPS 3PX -PH'JMF /FX'JMF %BUBCBTF -PH1SPDDFTTPS %C8SJUFS -PH'JMF8BUIDFS %C8SJUFS4VQFSWJTPS
  23. %JTQBUDIFS.BJMCPY w %JTQBUDIFS͸.BJMCPYʹ*NNVUBCMFͳϝοηʔδΛ௥Ճ͢Δ 4IBSE/PUIJOH ɻ"DUPS͸ .BJMCPYΛܦ༝ͯ͠ϝοηʔδΛॱ൪ʹऔಘ͢Δɻ։ൃऀ͸%JTQBUDIFS͕ར༻͢ΔεϨουΛ ҙࣝ͠ͳ͍ɻܾ·ͬͨ୯ҐͷϝοηʔδΛॲཧ͍ͯ͠Δࡍத͸ɺผͷϝοηʔδΛॲཧ͠ͳ͍ ͷͰɺඇಉظڥքΛҙ͍ࣝͯ͠Ε͹ɺಉҰΞΫλʔ಺Ͱ͸γϯάϧεϨουͷΑ͏ʹݟ͑Δɻ w "DUPS਺෼ͷεϨου਺͕ඞཁʹͳΔΘ͚Ͱ͸ͳ͍ɻϥΠτ΢ΣΠτɻඦສ"DUPS͸(#ఔ

    ౓ɻεϨουϞσϧͰ͸(#εϨουఔ౓ͱߟ͑Δͱେ͖ͳ͕ࠩ͋Δɻ w %JTQBUDIFS΍.BJMCPY͸ඞཁʹԠͯ͡ద੾ͳछྨͱઃఆΛબͿ͜ͱͰνϡʔχϯά͕Մೳɻ "DUPS .BJMCPY . . %JTQBUDIFS . "DUPS .BJMCPY . . %JTQBUDIFS . "DUPS .BJMCPY 9 9 9 %JTQBUDIFS͕ .BJMCPYʹϝο ηʔδΛ௥Ճ͢Δ 5ISFBE 5ISFBE ্ͰϝοηʔδΛ௥ Ճɻ "DUPS͸.BJMCPY ͔Βॱ൪ʹऔಘ͢ Δɻ 5ISFBE 5ISFBE ্ͰϝοηʔδΛ௥ Ճɻ
  24. σʔλϑϩʔͷൺֱ val result = (1 to 3).view
 .map { i

    => print(s"A: $i -> "); i }
 .map { i => print(s"B: $i -> "); i }
 .foldLeft(Seq.empty[Int])(_ :+ _)
 println(result) ਖ਼֨ίϨΫγϣϯ  """###-JTU     ඇਖ਼֨ίϨΫγϣϯ  "#"#"#-JTU     "LLB4USFBN  "#"#"#7FDUPS    val future = Source(1 to 3)
 .map { i => print(s"A: $i -> "); i }
 .map { i => print(s"B: $i -> "); i }
 .runWith(Sink.seq)
 println(Await.result(future, Duration.Inf)) "LLB4USFBN൛ ඪ४ίϨΫγϣϯ൛ ඇਖ਼֨ͷΑ͏ͳৼΔ෣͍ʹͳΔ͕ɺ ॲཧॱংʹґଘ͢ΔίʔυΛॻ͘ ΂͖Ͱ͸ͳ͍ɻࢀরಁ໌ͳؔ਺Ͱ هड़͢Δɻ
  25. ϑΝΠϧίϐʔͷྫ val inputFile = Paths.get(args(0))
 val outputFile = Paths.get(args(1)) 


    // ࢦఆͨ͠ύε͔ΒϑΝΠϧΛಡΈByteStringͱͯ͠ग़ྗ͢ΔSource
 val source: Source[ByteString, Future[IOResult]] = FileIO.fromPath(inputFile)
 
 // ByteStringͷೖྗΛड͚औΓɺࢦఆͨ͠ύεʹग़ྗ͢ΔSink
 val sink: Sink[ByteString, Future[IOResult]] = FileIO.toPath(outputFile, Set(CREATE, WRITE, APPEND)) 
 // SourceͱSinkΛ݁߹࣮ͯ͠ߦՄೳͳάϥϑΛੜ੒͢Δ
 val runnableGraph: RunnableGraph[Future[IOResult]] = source.to(sink)
 
 implicit val system = ActorSystem()
 implicit val ec = system.dispatcher
 implicit val materializer = ActorMaterializer()
 
 // ࣮ߦՄೳͳάϥϑΛ࣮ߦ͢Δɻ
 runnableGraph.run().foreach { result =>
 println(s"${result.status}, ${result.count} bytes read.")
 system.terminate()
 }
  26. "DUPS.BUFSJBMJ[FS w "DUPS൛ͷ.BUFSJBMJ[FS͸ɺ3VOOBCMF(SBQIΛ࣮ߦ͢Δ"DUPSʹม׵͢Δɻͨͩ͠ɺ BLLBSFNPUFʹ͸ରԠ͍ͯ͠ͳ͍ɻϩʔΧϧϊʔυ಺ͷΈͷαϙʔτɻ w 'JMF1VCMJTIFS͸ऴΘΓ͕དྷΔ·ͰϑΝΠϧ͔Β#ZUF4USJOHΛಡΉɻ w 'JMF4VCTDSJCFS͸'JMF1VCMJTIFS͔Βड͚औͬͨ#ZUF4USJOHΛϑΝΠϧʹॻ͖ࠐΉɻ w 'JMF1VCMJTIFS͕͢΂ͯͷϑΝΠϧΛಡΜͩΒ'JMF4VCTDSJCFSʹ0O$PNQMFUFΛૹͬ

    ͯఀࢭ͢Δɻ w 'JMF4VCTDSJCFS͕0O$PNQMFUFΛड͚औͬͨΒΦʔϓϯ͍ͯ͠Δ'JMF$IBOOFMΛด͡ ͯఀࢭ͢Δɻ 3VOOBCMF(SBQI 4PVSDF 4JOL 'JMF1VCMJTIFS 'JMF4VCTDSJCF 'JMF$IBOOFM 'JMF$IBOOFM 'JMF4PVSDF͔Β 4PVSDFΛฦ͢ 'JMF4JOL͔Β4JOLΛฦ ͢ 'JMF4PVSDF͕ 'JMF1VCMJTIFS "D UPS Λੜ੒͢Δ 'JMF4JOL͕ 'JMF4VCTDSJCFS "DU PS Λੜ੒͢Δ 'JMF1VCMJTIFS͕ 'JMF$IBOOFMΛੜ ੒͢Δ 'JMF4VCTDSJCFS͕ 'JMF$IBOOFMΛੜ੒ ͢Δ "DUPS.BUFSJBMJ[FS 4VCTDSJQUJPO
  27. #BDL1SFTTVSF w 4VCTDSJCFS͕ॲཧ͠੾Εͳ͍΄ͲͷλεΫΛ1VCMJTIFS͕ૹΔͱɺ .BJMCPY͕Φʔόʔϑϩʔ͢ΔͨΊɺ4VCTDSJCFS͔Βཁٻ͕͋ͬͨ ෼͚ͩΛૹΔΑ͏ʹ͢Δɻ͜ΕΛ#BDL1SFTTVSF എѹ੍ޚ ͱ͍͏ɻ ϑϩʔ੍ޚͷҰछɻ w ͨͱ͑͹ɺ'JMF4VCTDSJCFS͕ཁૉΛॲཧͰ͖ΔͳΒ'JMF4VCTDSJCFS

    ͕'JMF1VCMJTIFSʹ3FRVFTUϝοηʔδΛૹΔɻ'JMF1VCMJTIFS͸ಡΈ ࠐ·Εͨཁૉͷ#ZUF4USJOHΛ'JMF4VCTDSJCFSʹૹΔɻ 'JMF1VCMJTIFS 'JMF4VCTDSJCFS 'JMF$IBOOFM 'JMF$IBOOFM 3FRVFTU  PO/FYU CZUFT 3FBE 8SJUF
  28. ؆୯ͳ'MPXͷྫͱ.BUFSJBMJ[FE7BMVF val future = Source(1 to 10)
 .via(Flow[Int].map(_ * 2))


    .toMat(Sink.seq)(Keep.right).run()
 
 // ҎԼͱಉ͡ҙຯ // val future = Source(1 to 10)
 // .map(_ * 2)
 // .runWith(Sink.seq)
 3VOOBCMF(SBQI 4PVSDF 4JOL WBMTPVSDF4PVSDF<*OU /PU6TFE> 4PVSDF UP WBMTJOL4JOL</PUIJOH 'VUVSF<4FR<*OU>>> 4JOLTFR<*OU> UP.BU 4JOLTFR ,FFQSJHIU ͱͨ͠৔߹͸ӈଆͷ .BUFSJBMJ[FE7BMVFΛऔಘ͢Δ ,FFQMFGU͸ /PU6TFE ,FFQCPUIͱ͢Δ͜ͱ΋Մೳ .BUFSJBMJ[FE7BMVFͱ͸4PVSDF΍ 4JOL͕ఏڙ͢Δิॿ஋ɻܭࢉʹؔ ࿈͢Δ஋΍ɺ݁ՌΛؚΉ஋ͳͲɻ ϑΝΠϧίϐʔͷྫͰ͸ 'VUVSF<*03FTVMU>ɺ͜ͷྫͰ͸ 'VUVSF<4FR<*OU>>ͱͳΔɻ
  29. ([JQ$PNQSFTT'MPX class GzipCompressorStage extends GraphStage[FlowShape[ByteString, ByteString]] {
 val compressor =

    new GzipCompressor()
 val in: Inlet[ByteString] = Inlet("GzipCompressorStage")
 val out: Outlet[ByteString] = Outlet("GzipCompressorStage")
 
 override def shape: FlowShape[ByteString, ByteString] = FlowShape(in, out)
 
 @scala.throws[Exception](classOf[Exception])
 override def createLogic(inheritedAttributes: Attributes) = new GraphStageLogic(shape) {
 setHandler(in, new InHandler { // ্ྲྀ͔ΒͷByteStringΛѹॖͯ͠Լྲྀʹྲྀ͢
 @scala.throws[Exception](classOf[Exception])
 override def onPush(): Unit = 
 push(out, compressor.compressAndFlush(grab(in)))
 // ্ྲྀ͕ऴྃͨ͠Β࠷ޙͷByteStringΛѹॖͯ͠Լྲྀʹྲྀ͢
 @scala.throws[Exception](classOf[Exception])
 override def onUpstreamFinish(): Unit = { push(out, compressor.finish()); super.onUpstreamFinish() }
 })
 setHandler(out, new OutHandler {
 override def onPull(): Unit = {
 pull(in)
 }
 })
 }
 } (SBQI4UBHFΛ࢖͏ͱෳࡶͳ 4PVSDF 'MPX 4JOL͕ఆٛͰ͖Δ Χ ελϜεςʔδ ɻάϥϑͷߏஙఔ ౓ͳΒ͹(SBQI%4-Ͱ΋هड़Մೳɻ
  30. (;JQ$PNQSFTT'MPXΛ૊ΈࠐΉ val source: Source[ByteString, Future[IOResult]] = 
 FileIO.fromPath(inputFile)
 // GzipCompresssorStageΛFlowͱͯ͠ఆٛ͢Δ


    val flow: Flow[ByteString, ByteString, NotUsed] = 
 Flow.fromGraph(new GzipCompressorStage())
 // ByteStringͷೖྗΛड͚औΓɺࢦఆͨ͠ύεʹग़ྗ͢ΔSink
 val sink: Sink[ByteString, Future[IOResult]] = FileIO.toPath(outputFile, Set(CREATE, WRITE, APPEND))
 // SourceͱSinkΛ݁߹࣮ͯ͠ߦՄೳͳάϥϑΛੜ੒͢Δ
 val runnableGraph: RunnableGraph[Future[IOResult]] = source.via(flow).to(sink) TDBMB'JMF$PQZ8JUI([JQ)FMMP8PSMEUYU)FMMP8PSMEUYUH[ HVO[JQ)FMMP8PSMEUYUH[D )FMMP8PSME ΧελϜεςʔδΛετϦʔϜʹ ૊ΈࠐΉ৔߹͸GSPN(SBQIϝιο υΛ࢖͏ɻ
  31. (SBQI%4-ͷྫ val g = RunnableGraph.fromGraph(GraphDSL.create() { implicit builder: GraphDSL.Builder[NotUsed] =>


    
 import GraphDSL.Implicits._
 val in = Source(1 to 10)
 val out = Sink.ignore
 
 val bcast = builder.add(Broadcast[Int](2))
 val merge = builder.add(Merge[Int](2))
 
 val f1, f2, f3, f4 = Flow[Int].map(_ + 10)
 
 in ~> f1 ~> bcast ~> f2 ~> merge ~> f3 ~> out
 bcast ~> f4 ~> merge
 ClosedShape
 })
  32. "DUPSͱͷΠϯςάϨʔγϣϯ val (actorRef, future) = Source.actorRef[Int](Int.MaxValue, OverflowStrategy.fail)
 .map(_ * 2)


    .toMat(Sink.seq)(Keep.both).run()
 
 for {n <- 1 to 10} {
 actorRef ! n
 }
 actorRef ! Status.Success(1)
 
 println(Await.result(future, Duration.Inf)) "DUPSΛ4PVSDFʹ͢Δ͜ͱ͕Մೳɻͨͩ͠CBDLQSFTTVSF͸ޮ͔ ͳ͍ͷͰɺͦͷ৔߹͸"DUPS1VCMJTIFSΛ࢖͏ͱΑ͍ɻ
  33. BLLBIUUQαʔόଆͷىಈॲཧ object Main extends App with TodoWriteService with TodoReadService {


    
 private implicit val system = ActorSystem("akka-http-sample")
 
 override protected implicit val materializer = ActorMaterializer()
 
 private implicit val executionContext = system.dispatcher
 
 // … 
 private val route: Route = todoWriteRoute ~ todoReadRoute
 
 private val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
 
 sys.addShutdownHook {
 bindingFuture
 .map(_.unbind)
 .onComplete(_ => system.terminate())
 }
 
 } BLLBIUUQࣗମ΋BLLBTUSFBNΛ࢖࣮ͬͯ૷͞Ε͍ͯΔɻجຊతʹ ͸)UUQCJOE"OE)BOEMFͳͲʹ3PVUFΛ౉͚ͩ͢ɻ
  34. ίϯτϩʔϥ૬౰ͷϩδοΫ trait TodoWriteService extends Directives {
 
 implicit val timeout

    = Timeout(10 seconds)
 
 protected val todoAggregateRef: ActorRef
 
 val todoWriteRoute: Route = createTodo ~ updateTodo ~ deleteTodo
 
 private val createTodo: Route = {
 path("todos") {
 post {
 entity(as[CreateTodoRequestJson]) { requestBody =>
 val commandId = UUID.randomUUID()
 val todoId = TodoId(UUID.randomUUID())
 val future = (todoAggregateRef ? Create(commandId, todoId, requestBody.text))
 .mapTo[CreateSuccess]
 onSuccess(future) { res =>
 complete(CreateTodoResponseJson(res.id, res.aggregateId.value))
 }
 }
 }
 }
 }
 
 private val updateTodo: Route = ???
 private val deleteTodo: Route = ???
 
 } 3PVUJOH%4-ͰϧʔτΛهड़͢ΔɻΞΫλʔ ʹϝοηʔδύογϯά͠ɺͦͷ݁Ռ 'VUVSF ΛϨεϙϯεʹؚΊΔ͜ͱ͕Ͱ ͖Δɻ
  35. BLLBIUUQ BLLBTUSFBNͷ૊Έ߹Θͤ trait TodoReadService extends Directives {
 
 protected implicit

    val materializer: Materializer
 
 protected val todoDas: TodoDas
 
 protected val todoReadRoute: Route = getTodoById ~ getTodos
 
 private val getTodoById: Route = {
 pathPrefix("todos" / JavaUUID) { id =>
 get {
 val future = todoDas.findById(TodoId(id)).runWith(Sink.head)
 onSuccess(future) { res =>
 complete( GetTodoResponseJson(res.id.value, res.text, res.createAt, res.updateAt) )
 }
 }
 }
 }
 
 private val getTodos: Route = ???
 
 } 3FBDUJWF4USFBNTʹରԠͨ͠4MJDLͷ 4PVSDF %BUBCBTF1VCMJTIFS Λ"LLB4USFBNͷάϥϑʹ ૊ΈࠐΉ͜ͱ͕Ͱ͖Δɻ
  36. ·ͱΊ w ߴ͍ඇػೳཁ͕݅໰ΘΕΔγεςϜͰ࢖͑ΔҰͭͷߟ͑ํɻ͔͠͠ɺ՝୊΋ଟ͍ͱࢥ͏ɻ w ՝୊ w ϦΞΫςΟϒγεςϜΛαϙʔτ͢ΔϑϨʔϜϫʔΫ΍ϥΠϒϥϦ͸·ͩա౉ظɻͨͿΜɺ"LLB ͔&SMBOH051 &MJYJSʹ͸"LLB4USFBN૬౰ͷػೳ͕௥Ճ͞Εͭͭ͋Δ ͙Β͍͔͠ͳͦ͞͏ɻ

    w +7.্ݴޠͱͯ͠4DBMBΛֶͼͳ͕Β࢖͏͔ɺҰԠɺ"LLB͸+BWBͰ΋࢖͑·͢ʜ DBTF DMBTT͕ͳ͍ͷͰύλʔϯϚον͕ॻ͖ͮΒ͍ʁࣗલ࣮૷ͰؤுΔ͔͠ͳ͍ ɻ4QSJOH 3FBDUPSʹ͸4VQFSWJTJPO͕ͳ͍ʁ w ϝιουۦಈʹ׳Ε͗ͨ͢ΤϯδχΞʹͱͬͯ͸ɺϝοηʔδۦಈ͸೉͘͠ݟ͑Δ͔΋͠Εͳ ͍ɻ w "DUPSؒ͸ϝοηʔδۦಈͰ"DUPS಺෦͸ϝιουۦಈͰ࢖͍෼͚Δɻ w ҐஔಁաੑͷຊྖΛൃش͢Δʹ͸BLLBDMVTUFS TIBSEJOH BLLBQFSTJTUFODFΛಋೖ͢Δඞཁ͕ ͋Δ͕ɺωοτϫʔΫ෼அʹΑͬͯΫϥελʔ ͕෼அ͢ΔՄೳੑ͕͋Δ 4QMJU#SBJO  w -#ࣾͷιϦϡʔγϣϯ΋͋Δ͕ʜɻγϯά ϧ";Ͱӡ༻ͨ͠ํ͕͍͍͔΋ɻ w ͦ΋ͦ΋"DUPSಉ࢜ͷઃܭΛͲ͏ͨ͠ΒΑ͍ͷ ͔ʁ w ӈͷຊΛಡΈ·͠ΐ͏