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
Monixと常駐プログラムの勘どころ
Search
Ishikawa Ryuto
December 13, 2024
Programming
980
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Monixと常駐プログラムの勘どころ
【オフライン】Scalaわいわい勉強会 #4【東京】
https://scala-tokyo.connpass.com/event/335477/
Ishikawa Ryuto
December 13, 2024
More Decks by Ishikawa Ryuto
See All by Ishikawa Ryuto
Scalaが支える4RAPの認証認可基盤
stoneream
0
96
Other Decks in Programming
See All in Programming
LoopHub - ローカルで動く GitHub で、AI と共同開発
jugyo
1
550
[GoCon2026] When Goroutines Are Not Enough: Runtime Locality in High-Throughput Go
takehaya
6
2.2k
技術的負債の返済は、AI時代の複利で効く投資 — 経営としての意思決定とその遂行
curekoshimizu
0
1.3k
AHC070解法紹介
eijirou
0
120
GraphRAGのKnowledge Graphを 直接!見る/View-GraphRAG's-KnowledgeGraph-directly!
tyumugi1113
1
320
Starting & Sustaining Code-Based E2E Testing for Non-Coding QA Teams( #jasstniigata )
teyamagu
PRO
1
260
マイコン向けの軽量Ruby「PicoRuby」で各種デバイスを制御するネイティブアプリの実現手法
bash0c7
0
410
巨大モノリシックアプリ モダン化大作戦
ktcryomm
0
1k
AgentCore CLI で進化した AWS での AI エージェントの作り方 : 必要な機能を必要な時に
icoxfog417
PRO
3
340
モデルのリファクタリングが難しいと思ったら、そもそも複雑だったのはビジネス仕様だった ? / is-the-business-domain-the-real-complexity
hatsu38
0
270
cdk deploy JawsSonic #MARATHONしながらAWSリソースをデプロイしてみよう
akihisaikeda
2
130
『寄り添うラジオ』をAIで作る 体験価値から逆算した、会話しないUXと品質設計
theoriatec2024
3
180
Featured
See All Featured
Building Flexible Design Systems
yeseniaperezcruz
330
41k
Scaling GitHub
holman
464
140k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
600
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
2
2.1k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3.1k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
290
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
12k
HTML-Aware ERB: The Path to Reactive Rendering @ RubyCon 2026, Rimini, Italy
marcoroth
5
660
ラッコキーワード サービス紹介資料
rakko
1
4.9M
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
330
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
360
Transcript
Monixと 常駐プログラムの 勘どころ 2024/12/13 Ishikawa Ryuto
自己紹介 石川 龍斗 (Ishikawa Ryuto) @stoneream 株式会社FOLIO (2023~) バックエンドエンジニアとしてScalaを書いている Scala歴は5年目くらい
「常駐プログラム」って何? 文字通り「一度起動したらそのまま立ち上げておくプログラム 」 背景として... 「Spotify アーティストの新曲を巡回・通知くん」を作った 主な機能 • フォロー中アーティストの取り込み (バッチ)
• アーティストのリリースを巡回 (毎日) • Discordへの通知 (随時) 以降、「巡回くん」
今日のお話 Monixの書き心地が良かった • エラーハンドリング • リトライ処理 • 処理の並列実行 常駐プログラムが常駐してもらうためのの勘どころ •
設計として考慮しておくと良さそうなこと • 実装としてやっておくと良かったこと 巡回くんでの実例を交えて紹介! 何度か作り直している ... 「こうすれば良かった ...」の話
簡単にMonixについて
val t1 = Task[Int] { 10 } val t2 =
Task[Int] { 20 } // Task同士の合成が可能 val combinedTask = for { t1Result <- t1 t2Result <- t2 } yield t1Result + t2Result // 30 combinedTask.runToFuture.foreach(println) // 並列で実行が可能 val tasks = Task.parSequence(Seq(t1, t2)) // 10 // 20 tasks.runToFuture.foreach(println) 処理のかたまりを “Task” という単位で扱い抽象化
val t1 = Task[Int] { 10 } val t2 =
Task[Int] { 20 } // Task同士の合成が可能 val combinedTask = for { t1Result <- t1 t2Result <- t2 } yield t1Result + t2Result // 30 combinedTask.runToFuture.foreach(println) // 並列で実行が可能 val tasks = Task.parSequence(Seq(t1, t2)) // 10 // 20 tasks.runToFuture.foreach(println) Task は遅延評価
val t1 = Task[Int] { 10 } val t2 =
Task[Int] { 20 } // Task同士の合成が可能 val combinedTask = for { t1Result <- t1 t2Result <- t2 } yield t1Result + t2Result // 30 combinedTask.runToFuture.foreach(println) // 並列で実行が可能 val tasks = Task.parSequence(Seq(t1, t2)) // 10 // 20 tasks.runToFuture.foreach(println) 非同期に実行することも
簡単に Monix について 処理のかたまりを Task という単位で扱い抽象化 非同期処理をシンプルに書くための機能を提供してくれる リトライやエラーハンドリングのための機能が充実している点も魅力 (後述) Cats
Effect の一部機能は Monix の影響を受けている、らしい >> cats.effect.IOとmonix.eval.Taskはとてもよく似ていて、しかも私は両方の開発に携わることになった ので、Taskで決めた設計は結局IOでも採用することになった。 とはいえ、IOはシンプルで信頼性の高い、 純粋なリファレンス実装になるように設計されている。 (Monix vs Cats-Effect より deepL翻訳)
勘所 1
エラーは基本的には自動回復 当たり前ですが...。 考慮する観点は以下の2つ? エラーの種類 • リトライで問題ない • 自動復旧できない ◦ 想定内のエラー?
◦ 想定外のエラー? リトライの種類 • 即座 • n秒後 • しない リトライ回数の制限 処理全体のタイムアウト なども プロダクション環境下では 復旧のための参考情報になる
Monixにおけるエラーハンドリングとリトライ Taskで発生した例外は自動的に捕捉してくれる! 捕まえたエラーを良い感じに扱うメソッドがいくつか生えている ・Task#onErrorHandleWith[B >: A](f: (Throwable) => Task[B]): Task[B]
例外の型や内容から別のTaskを作成する ・Task#onErrorRestartIf(p: (Throwable) => Boolean): Task[A] 例外の型や内容が特定の条件にマッチした場合にリトライする・しない ・Task#onErrorRestart(maxRetries: Long): Task[A] エラー発生時に任意の回数まではリトライする
巡回くんの例
def retryWhenTooManyRequests[A](task: Task[A], maxRetries: Int): Task[A] = { task.onErrorHandleWith {
case e: TooManyRequestsException => if (maxRetries > 0) { val retryAfter = e.getRetryAfter retryWhenTooManyRequests(task, maxRetries - 1) .delayExecution(retryAfter.seconds) } else { Task.raiseError(e) } case e => Task.raiseError(e) } } レートリミットに引っかかった
def retryWhenTooManyRequests[A](task: Task[A], maxRetries: Int): Task[A] = { task.onErrorHandleWith {
case e: TooManyRequestsException => if (maxRetries > 0) { val retryAfter = e.getRetryAfter retryWhenTooManyRequests(task, maxRetries - 1) .delayExecution(retryAfter.seconds) } else { Task.raiseError(e) } case e => Task.raiseError(e) } } 例外情報に含まれる情報を 参考にリトライを試みる
def retryWhenTooManyRequests[A](task: Task[A], maxRetries: Int): Task[A] = { task.onErrorHandleWith {
case e: TooManyRequestsException => if (maxRetries > 0) { val retryAfter = e.getRetryAfter retryWhenTooManyRequests(task, maxRetries - 1) .delayExecution(retryAfter.seconds) } else { Task.raiseError(e) } case e => Task.raiseError(e) } } それ以外の例外は諦める 何回やっても駄目なときは諦める
勘所 2
処理は途中で落ちる、絶対に落ちる イチからやり直しはしたくない • メモリが足りなくなった • APIのレートリミットに引っかかった • 間違えてKillした ほしい機能 •
途中から処理を再開できるようにする • 不必要な処理の再実行の抑制する 全部 実際に起きた
巡回くんの例 「新着リリース巡回」機能の場合... 1. 巡回スケジュールを作成し、データベースに処理待ちとして積む 2. 処理待ちから数件ずつ取って処理する 設計する際は... 各タイミングでの時刻も保持することもポイント! • 処理を積んだタイミング
• 処理の開始 • 処理の正常終了・異常終了 処理が始まっていない! 終わっていない!など エラー検知に役立ちます
ありがとうございました
リンク集 Monix https://github.com/monix/monix Monix vs Cats-Effect https://monix.io/blog/2018/03/20/monix-vs-cats-effect.html softwaremill/retry https://github.com/softwaremill/retry Scala
Advent Calendar 2024 https://qiita.com/advent-calendar/2024/scala FOLIO Advent Calendar 2024 https://adventar.org/calendars/10315 こちらもぜひご覧ください m(_ _)m これもおすすめ