Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Akka Typed - 型安全にメッセージパッシングする! / Akka Typed - t...
Search
hayasshi
November 10, 2018
Technology
3k
6
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Akka Typed - 型安全にメッセージパッシングする! / Akka Typed - typesafe messaging
hayasshi
November 10, 2018
More Decks by hayasshi
See All by hayasshi
Chatwork で Akka をどうつかっているのか なぜつかっているのか / Why Akka, How Akka in Chatwork
hayasshi
1
620
とある会社のビルドデプロイ / A certain company's application building
hayasshi
0
390
Scala / refined で`型く`表明プログラミング / Programing with type level assertion
hayasshi
2
990
AWS Dev Day Challenge (2018-11-02) - ChatWork Suita
hayasshi
2
770
Scala and Akka apps on Kubernetes in ChatWork
hayasshi
0
2.7k
Other Decks in Technology
See All in Technology
スキマバイトという雇用形態は存在しないので、雇用期間1日のアルバイト契約を事業者とワーカーが結ぶ手続きを支えるのがタイミーなんです
akitoshiga
0
200
QA4AI 2026-Oct 生成AI時代の品質保証
tokuty
1
860
二歩目のフロントエンド・ウェブアクセシビリティ
camiha
2
570
How to Design Configuration for Rails Applications
willnet
1
780
パスキーの自動テストはどこまでいけるのか
teamlab
PRO
0
210
しろおびから始める!ログ活用の第一歩
shumei_ito
0
950
Browser Spec: Testing Hotwire with Ruby
takahashim
1
120
サブエージェントと Claude Mods で作る独自 Advisor ツールの話
kenichiodo
2
160
脆弱性診断って、何をしているの? 〜弱点を見つけて、会社の改善につなげるまで〜
keeg
0
920
実践!Cloud Run ハンズオン!! / Cloud Run handson
y0hgi
2
280
Kiro Crewをはじめよう
kizawa2020
1
160
Persisting Massive Data with Rails ~Designing for 60 billion rows, and fighting the bottlenecks~ Railsで挑む大量データ永続化 〜600億件を永続化するための設計とボトルネックとの戦い〜
occhi
0
730
Featured
See All Featured
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.6k
WCS-LA-2024
lcolladotor
0
890
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
440
AI: The stuff that nobody shows you
jnunemaker
PRO
10
1.2k
A designer walks into a library…
pauljervisheath
211
25k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
220
Context Engineering - Making Every Token Count
addyosmani
9
1.2k
Music & Morning Musume
bryan
48
7.4k
Product Roadmaps are Hard
iamctodd
55
13k
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
750
Odyssey Design
rkendrick25
PRO
2
870
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
280
Transcript
Akka Typed 型安全にメッセージパッシングする! 2018-11-10 Scala 関西Summit 2018 1
自己紹介 林 大介 Twitter: @hayasshi_ GitHub: hayasshi ChatWork 株式会社 Scala
2.9 系から使い始め(2013 年頃) 型好き、Akka 好き 2018-11-10 Scala 関西Summit 2018 2
お話すること Akka や アクターモデルについて簡単におさらい Akka Typed について 各パターンでの比較 アクター生成とAsk スーパービジョン
ライフサイクル 他のモジュールとの統合 2018-11-10 Scala 関西Summit 2018 3
お話しない( できない) こと Akka Actors とのパフォーマンス比較 簡易なものでもやりたかった!スミマセン Akka Typed の導入事例
Akka Typed への移行戦略について 2018-11-10 Scala 関西Summit 2018 4
Akka と アクターモデル 2018-11-10 Scala 関西Summit 2018 5
メニーコア時代における、並行・分散処理をおこなう アプリケーションを構築するためのツールキット 一台のマシン上でのアプリケーションから 複数台のマシンでの分散処理やクラスタリングなどを構築するため のモジュールが用意されている これらの根底にあるものは アクターモデル 2018-11-10 Scala 関西Summit
2018 6
アクターモデル 1973 年 カール・ヒューイット氏が発表した 並行処理を行うための計算モデル 全てのものはアクターである 全てのものはオブジェクトであると同様な考え方 違いは本質的に並行性を備えているということ アクターはメッセージに対する振る舞いを持つ アクター間のメッセージのやり取りで計算を行う
2018-11-10 Scala 関西Summit 2018 7
アクターモデル 2018-11-10 Scala 関西Summit 2018 8
詳しくは 2018-11-10 Scala 関西Summit 2018 9
お話する前提のバージョン 下記のバージョンで動作確認等を行っています。 val scalaVersion = "2.12.7" val akkaVersion = "2.5.17"
2018-11-10 Scala 関西Summit 2018 10
Akka Actors Akka の全ての基礎となる、根底のモジュール JVM 上でアクタープログラミングを行うことができる JVM で並行処理をおこなうにあたっての大変な部分を隠蔽し、 ロジックに集中できる 2018-11-10
Scala 関西Summit 2018 11
Akka Actors akka-scala-seed.g8 class Greeter(message: String, printerActor: ActorRef) extends Actor
{ import Greeter._ import Printer._ var greeting = "" def receive: Receive = { case WhoToGreet(who) => greeting = message + ", " + who case Greet => printerActor ! Greeting(greeting) } } 2018-11-10 Scala 関西Summit 2018 12
Akka Actors val system: ActorSystem = ActorSystem("helloAkka") val printer: ActorRef
= system.actorOf(Printer.props, "printerActor") val howdyGreeter: ActorRef = system.actorOf(Greeter.props("Howdy", printer), "howdyGreeter") val goodDayGreeter: ActorRef = system.actorOf(Greeter.props("Good day", printer), "goodDayGreeter") howdyGreeter ! WhoToGreet("Akka") howdyGreeter ! Greet // Howdy, Akka howdyGreeter ! WhoToGreet("Scala") howdyGreeter ! Greet // Howdy, Scala goodDayGreeter ! WhoToGreet("Play") goodDayGreeter ! Greet // Good day, Play 2018-11-10 Scala 関西Summit 2018 13
LGTM! しかし気をつけなければいけないことも... 2018-11-10 Scala 関西Summit 2018 14
Akka Actors val system: ActorSystem = ActorSystem("helloAkka") val printer: ActorRef
= system.actorOf(Printer.props, "printerActor") val howdyGreeter: ActorRef = system.actorOf(Greeter.props("Howdy", printer), "howdyGreeter") val goodDayGreeter: ActorRef = system.actorOf(Greeter.props("Good day", printer), "goodDayGreeter") howdyGreeter ! Greeting("Akka") howdyGreeter ! Greeting("Scala") goodDayGreeter ! Greeting("Play") なんか動きそう。コンパイルも通る。でも動かない... 2018-11-10 Scala 関西Summit 2018 15
tell ( ! ) メソッド型安全じゃない問題 trait ScalaActorRef { ref: ActorRef
⇒ def !(message: Any)(implicit sender: ActorRef = Actor.noSender): Unit } type Receive = PartialFunction[Any, Unit] trait Actor { def receive: Receive } アクター定義時に指定していないメッセージを受け取れてしまう ( コンパイルできてしまう) コードベースが大規模になってくると間違ったメッセージを送って しまう可能性が高くなる 2018-11-10 Scala 関西Summit 2018 16
型安全じゃない 2018-11-10 Scala 関西Summit 2018 17
Akka Typed 2018-11-10 Scala 関西Summit 2018 18
Akka Typed Akka Actors のメッセージパッシングを 型安全に行うためのモジュール Akka Actors の置き換えになる 基本的な部分のAPI
はだいたい固まっている 他モジュールとの統合API の部分を中心に細かな変更が続いている 2018-11-10 Scala 関西Summit 2018 19
Akka Typed libraryDependencies += "com.typesafe.akka" %% "akka-actor-typed" % akkaVersion アクターの定義は、振る舞い
Behavior を定義する 振る舞いは、次の振る舞いを返す入れ子構造になっている import akka.actor.typed.Behavior import akka.actor.typed.scaladsl.{ActorContext, Behaviors} case class Greet(whom: String) val greeterBehavior: Behavior[Greet] = Behaviors.receive { (ctx: ActorContext[Greet], msg) => ctx.log.info("Hello {}!", msg.whom) Behaviors.same } 2018-11-10 Scala 関西Summit 2018 20
Akka Typed アクターは振る舞い Behavior から生成される import akka.actor.typed.ActorSystem val greeter =
ActorSystem(greeterBehavior, "greeter") greeter ! Greet("Akka") // Hello Akka! case class Greeting(whom: String) greeter ! Greeting("Akka") // compile error ( ActorSystem もActorRef[T] を継承している) 型安全にメッセージパッシングできる! 2018-11-10 Scala 関西Summit 2018 21
Akka Typed - 状態 def counterBehavior(current: Int): Behavior[Int] = Behaviors.receiveMessage
{ c => val count = current + c println(count) counterBehavior(count) } val counter = ActorSystem(counterBehavior(0), "counter") counter ! 1 // 1 counter ! 3 // 4 状態は再帰をつかって表現する よりイミュータブルな振る舞いとして扱うことができる 2018-11-10 Scala 関西Summit 2018 22
なるほど良さそうに見える 型安全にメッセージパッシングできることはわかった しかし、Akka Actors に比べ 大きくコーディングスタイルが変わっている Akka Actors でよく使われる アクタープログラミングのパターンをどう記述していくか比較する
2018-11-10 Scala 関西Summit 2018 23
注意 これからのサンプルコードは資料の都合上、好ましくない書き方 をしているコードがあります 特に Akka Actors で Props を利用側が直接使っている箇所は 注意してください
Props にインスタンスを利用側から渡すと、利用側でインスタン スの状態を書き換えることができてしまいます // ダメゼッタイ val actor = new Greeter(...) val props = Props(actor) val actorRef = system.actorOf(props, "child") actor.greeting = "hoge" 2018-11-10 Scala 関西Summit 2018 24
パターン比較 アクター生成とAsk 2018-11-10 Scala 関西Summit 2018 25
アクター生成とAsk - Akka Actors class Producer extends Actor { def
receive: Receive = { case p: Props => val child = context.actorOf(p) context.watch(child) sender() ! context.actorOf(p) } } class Printer extends Actor { def receive: Receive = { case s: String => println(s) } } 2018-11-10 Scala 関西Summit 2018 26
アクター生成とAsk - Akka Actors val system = ActorSystem() val producer
= system.actorOf(Props(classOf[Producer])) import akka.pattern.ask implicit val ec = system.dispatcher implicit val timeout: Timeout = Timeout(3.seconds) val printer: Future[ActorRef] = (producer ? Props(classOf[Printer])).mapTo[ActorRef] for (printerRef <- printer) { printerRef ! "Hello" } 2018-11-10 Scala 関西Summit 2018 27
アクター生成とAsk - Akka Actors アクター生成 ActorSystem.actorOf , ActorContext.actorOf アクターの内部どこでも生成することができる Ask
import akka.pattern.ask で ask メソッド( ? ) を使えるようになる ask メソッドの返り値は Future[Any] のため mapTo をつかい、型を変換する ( 返ってくる実際の型と異なれば実行時エラー) 28
アクター生成とAsk - Akka Typed val printerBehavior: Behavior[String] = Behaviors.receiveMessage {
msg => println(msg) Behaviors.same } val producerBehavior: Behavior[SpawnProtocol] = Behaviors.receive { (ctx, msg) => msg match { case Spawn(bhvr, name, props, replyTo) => val ref = ctx.spawn(bhvr, name, props) ctx.watch(ref) replyTo ! ref } Behaviors.same } 2018-11-10 Scala 関西Summit 2018 29
アクター生成とAsk - Akka Typed アクター生成 ActorContext[T].spawn 振る舞いのなか( コンテキストのあるスコープ) で 生成することができる
SpawnProtocol はアクター生成するための組み込みメッセージ 対応する振る舞いも標準で用意されている SpawnProtocol.behavior 2018-11-10 Scala 関西Summit 2018 30
アクター生成とAsk - Akka Typed val producerBehavior: Behavior[SpawnProtocol] = Behaviors.receive {
(ctx, msg) => msg match { case Spawn(bhvr, name, props, replyTo) => val ref = ctx.spawn(bhvr, name, props) ctx.watch(ref) replyTo ! ref } Behaviors.same } val spawnBehavior = SpawnProtocol.behavior val producer = ActorSystem(spawnBehavior, "producer") ただし ActorContext[T].watch を差し込めない 2018-11-10 Scala 関西Summit 2018 31
アクター生成とAsk - Akka Typed val producer = ActorSystem(producerBehavior, "producer") import
akka.actor.typed.scaladsl.AskPattern._ implicit val ec = producer.executionContext implicit val timeout: Timeout = Timeout(3.seconds) implicit val scheduler: Scheduler = producer.scheduler val printer: Future[ActorRef[String]] = producer ? SpawnProtocol.Spawn(printerBehavior, "printer") for (printerRef <- printer) { printerRef ! "Hello" } 2018-11-10 Scala 関西Summit 2018 32
アクター生成とAsk - Akka Typed Ask import akka.actor.typed.scaladsl.AskPattern._ で、 ask メソッド(
? ) を使えるようになる ActorRef[T] から実際の型が返る def ?[U](replyTo: ActorRef[U] ⇒T)(implicit...): Future[U] 戻し先となる ActorRef[U] をメッセージに含める case class Request(s: String, replyTo: ActorRef[Response]) server ?(ref => Request("data", ref) server ? (Request("data", _)) 2018-11-10 Scala 関西Summit 2018 33
アクター生成とAsk - 比較まとめ アクター生成 大きな違いはない Typed は ActorSystem ( ヒエラルキートップ)
からの 子アクター生成がメッセージ経由になる Ask 返ってくるメッセージに型がある! ask メソッドで送るメッセージに戻り先の ActorRef[U] を含める必要がある ( 送り先のActorRef[T] も受け付けれる必要がある) 2018-11-10 Scala 関西Summit 2018 34
パターン比較 スーパービジョン 2018-11-10 Scala 関西Summit 2018 35
スーパービジョンとは アクターには親子関係があり、アクターヒエラルキーを構成する 子アクターがクラッシュした際に、親アクターが子アクターをどう 扱うかを管理する仕組み 適切なエラーハンドリングを行い、状態を復元したり、再起動させ たり、安全に停止させることで、ヒエラルキー全体の自己復元力, 耐 障害性を高める 2018-11-10 Scala
関西Summit 2018 36
スーパービジョン - Akka Actors class Supervisor extends Actor { override
val supervisorStrategy: SupervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1.minute) { case _: ArithmeticException ⇒ Resume case _: NullPointerException ⇒ Restart case _: IllegalArgumentException ⇒ Stop case _: Exception ⇒ Escalate } def receive: Receive = { case p: Props ⇒ sender() ! context.actorOf(p) } } class Child extends Actor { def receive: Receive = { case ex: Exception ⇒ throw ex 37
スーパービジョン - Akka Typed val childBehavior: Behavior[Exception] = Behaviors.receiveMessage(throw _)
val supervisorBehavior: Behavior[Exception] = Behaviors.supervise { Behaviors.supervise { Behaviors.supervise { childBehavior }.onFailure[ArithmeticException](SupervisorStrategy.resume) }.onFailure[NullPointerException]( SupervisorStrategy.restartWithLimit( maxNrOfRetries = 10, withinTimeRange = 1.minute ) ) }.onFailure[IllegalArgumentException](SupervisorStrategy.stop) 2018-11-10 Scala 関西Summit 2018 38
スーパービジョン Actors Typed 戦略定義位置 親アクター Behavior への組み込み 戦略種別 OneForOneStrategy AllForOneStrategy
OneForOneStrategy 対応内容種別 Resume , Restart , Stop Escalate Resume , Restart , Stop 再起動制御 あり あり デフォルトの戦略 OneForOneStrategy で Restart OneForOneStrategy で Stop 2018-11-10 Scala 関西Summit 2018 39
パターン比較 ライフサイクル 2018-11-10 Scala 関西Summit 2018 40
アクターのライフサイクルとは アクターには生成から停止して削除されるまでのライフサイクルが ある ライフサイクルの各ポイントでフックでき、様々な処理を追加でき る let it crash の思想に従い、問題が起きたときのハンドリングを設計 し、組み込むことができる
スーパービジョンと組み合わせることでアプリケーション全体の耐 障害性を高める 2018-11-10 Scala 関西Summit 2018 41
アクターのライフサイクルとは Akka 実践バイブルより引用 2018-11-10 Scala 関西Summit 2018 42
ライフサイクル - Akka Actors class IdPrinterActor extends Actor { override
def preStart(): Unit = { println(s"preStart ${self.path}") super.preStart() } override def preRestart(reason: Throwable, message: Option[Any]): Unit = { println(s"preRestart $message ${self.path}") super.preRestart(reason, message) } override def postRestart(reason: Throwable): Unit = { println(s"postRestart ${reason.getMessage} ${self.path}") super.postRestart(reason) } override def postStop(): Unit = { println(s"postStop ${self.path}") super.postStop() } 2018-11-10 Scala 関西Summit 2018 43
ライフサイクル - Akka Actors class IdPrinterActor extends Actor { //
...lifecycle hook override def receive: Receive = { case Message(id) => id match { case 0L => throw new Exception("Id is zero!") case 9L => context.stop(self) case _ => println(id) } } } 2018-11-10 Scala 関西Summit 2018 44
ライフサイクル - Akka Actors object IdPrinterActor { def name(id: Long):
String = s"id-printer-$id" def props: Props = Props(classOf[IdPrinterActor]) } val system = ActorSystem() val printer1 = system.actorOf(IdPrinterActor.props, IdPrinterActor.name(1L)) printer1 ! Message(1L) val printer0 = system.actorOf(IdPrinterActor.props, IdPrinterActor.name(0L)) printer0 ! Message(0L) val printer9 = system.actorOf(IdPrinterActor.props, IdPrinterActor.name(9L)) printer9 ! Message(9L) 2018-11-10 Scala 関西Summit 2018 45
ライフサイクル - Akka Actors 見やすいように調整しています preStart akka://default/user/id-printer-1 1 preStart akka://default/user/id-printer-0
[ERROR] [11/08/2018 23:12:35.727] [default-akka.actor.default-dispatcher-4] [akka: java.lang.Exception: Id is zero! at ... preRestart Some(Message(0)) akka://default/user/id-printer-0 postStop akka://default/user/id-printer-0 postRestart Id is zero! akka://default/user/id-printer-0 preStart akka://default/user/id-printer-0 preStart akka://default/user/id-printer-9 postStop akka://default/user/id-printer-9 2018-11-10 Scala 関西Summit 2018 46
ライフサイクル - Akka Typed val idPrintBehavior: Behavior[Message] = Behaviors.supervise {
Behaviors.setup[Message] { ctx => println(s"start ${ctx.self.path}") Behaviors.receiveMessage[Message] { msg => msg.id match { case 0L => throw new Exception("Id is zero!") case 9L => Behaviors.stopped case _ => println(msg.id);Behaviors.same } }.receiveSignal { case (context, PreRestart) => println(s"preRestart ${context.self.path}");Behaviors.same case (context, PostStop) => println(s"postStop ${context.self.path}");Behaviors.same } } }.onFailure(SupervisorStrategy.restart) 2018-11-10 Scala 関西Summit 2018 47
ライフサイクル - Akka Typed def idPrinterName(id: Long): String = s"id-printer-${id.toString}"
val system = ActorSystem(SpawnProtocol.behavior, "lifecycle") import akka.actor.typed.scaladsl.AskPattern._ implicit val ec: ExecutionContext = system.executionContext implicit val timeout: Timeout = Timeout(3.seconds) implicit val scheduler: Scheduler = system.scheduler for { printer1 <- system ? SpawnProtocol.Spawn(idPrintBehavior, idPrinterName(1L)) printer0 <- system ? SpawnProtocol.Spawn(idPrintBehavior, idPrinterName(0L)) printer9 <- system ? SpawnProtocol.Spawn(idPrintBehavior, idPrinterName(9L)) } { printer1 ! Message(1L) printer0 ! Message(0L) printer9 ! Message(9L) } 2018-11-10 Scala 関西Summit 2018 48
ライフサイクル - Akka Typed 見やすいように調整しています setup akka://lifecycle/user/id-printer-1 1 setup akka://lifecycle/user/id-printer-0
preRestart akka://lifecycle/user/id-printer-0 setup akka://lifecycle/user/id-printer-0 [ERROR] [11/08/2018 23:51:35.515] [lifecycle-akka.actor.default-dispatcher-2] [ java.lang.Exception: Id is zero! at ... setup akka://lifecycle/user/id-printer-9 postStop akka://lifecycle/user/id-printer-9 2018-11-10 Scala 関西Summit 2018 49
ライフサイクル Actors Typed フック定義 override して拡張 super 呼び出しが必須 receiveSignal にて
Behavior を拡張 フック箇所の種類 preStart , postStop preRestart , postRestart PreRestart , PostStop 再起動時の フック箇所 preRestart postStop postRestart preStart PreRestart 2018-11-10 Scala 関西Summit 2018 50
他のモジュールとの統合 2018-11-10 Scala 関西Summit 2018 51
他のモジュールとの統合 Akka Streams との統合用API を含むモジュールが提供されている libraryDependencies += "com.typesafe.akka" %% "akka-stream-typed"
% akkaVersion ActorSource や ActorSink などのコンポーネントをつかい バッファや OverflowStrategy を設定して Akka Streams の Graph に Akka Actors を組み込むことができる 2018-11-10 Scala 関西Summit 2018 52
他のモジュールとの統合 その他のモジュールとの統合API も絶賛開発されていっています ( 主にクラスター関連) "com.typesafe.akka" %% "akka-cluster-typed" % akkaVersion
"com.typesafe.akka" %% "akka-cluster-sharding-typed" % akkaVersion "com.typesafe.akka" %% "akka-persistence-typed" % akkaVersion 2018-11-10 Scala 関西Summit 2018 53
他のモジュールとの統合 詳しくは公式ドキュメントやリリースノートを参照 https://doc.akka.io/docs/akka/current/typed/index.html https://akka.io/blog/news-archive.html 2018-11-10 Scala 関西Summit 2018 54
まとめ 2018-11-10 Scala 関西Summit 2018 55
まとめ Akka Typed になり より型安全にコーディングができるようになった コーディングスタイルが大きく変わるので切り替えが必要 細かな部分で Akka Actors と挙動がことなる
他のモジュールとの統合API も充実してきている アクタープログラミングの本質的な部分は変わっていない 2018-11-10 Scala 関西Summit 2018 56
参考・引用 Akka Documentation Akka 実践バイブル Wikipedia アクターモデル 2018-11-10 Scala 関西Summit
2018 57