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
分散型タスクスケジューリングシステム
Search
NearMeの技術発表資料です
PRO
November 24, 2023
Programming
130
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
分散型タスクスケジューリングシステム
NearMeの技術発表資料です
PRO
November 24, 2023
More Decks by NearMeの技術発表資料です
See All by NearMeの技術発表資料です
AIエージェントのための 隔離された安全なインフラ設計
nearme_tech
PRO
0
22
Claude Code × git worktree で並列開発 (続き) -差分のサービスだけを併設する-
nearme_tech
PRO
1
69
Claude Code × git worktree で並列開発 — サブモジュール構成のリポジトリで成立させる —
nearme_tech
PRO
0
79
LLM + 強化学習
nearme_tech
PRO
0
37
PosthogのA/Bテスト機能の紹介
nearme_tech
PRO
1
110
AIフレンドリーなプロダクトに向けて
nearme_tech
PRO
2
70
初めてのLean言語
nearme_tech
PRO
0
110
Apache Airflow Workflow orchestration without turning cron into spaghetti
nearme_tech
PRO
2
50
実務で役立つ幾何学 ボロノイ図の基礎から グラフ・ネットワーク応用まで
nearme_tech
PRO
1
93
Other Decks in Programming
See All in Programming
ChromeでローカルLLM
ryu1013
0
140
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
5
5.2k
設計次第でAIコードの読む量は減らせる / designing-for-code-reading
minodriven
35
17k
現場と育てるRailsモデリング 〜Spreadsheetから始めたモデル設計〜
siroemk
2
590
FactoryBotをやめればRSpecは速くなるのか?
yuta_onishi_97
0
270
[2026-09-26]空論ジェネリックプロセス~テスト資産とAIで紡ぐ、再現可能なパフォーマンスチューニングの話~
tosite
0
270
S3 TablesのIcebergデータに、AIエージェントからアクセスしてみた / 20261016developersio2026joetsu-accessing-iceberg-in-s3tables-via-agent
kasacchiful
PRO
0
150
Apple Intelligence を用いた個人情報誤送信防止、及びユーザーリクエスト体験の改善について
yukiny
0
350
コードで差別化できない時代の ソフトウェアエンジニアリング / Software Engineering in an Era Where Code Doesn’t Differentiate
kishida
2
180
SREの越境 / SRE Collaboration
y0hgi
2
310
AmebaブログはKMPから卒業します
kmars0605
0
180
Kotlinの15年とServer-Side Kotlin
n_takehata
1
150
Featured
See All Featured
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.8k
A Soul's Torment
seathinner
8
3.8k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
SEO for Brand Visibility & Recognition
aleyda
0
4.8k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.4k
Paper Plane (Part 1)
katiecoart
PRO
2
12k
Navigating Weather and Climate Data
rabernat
0
560
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
63
46k
Believing is Seeing
oripsolob
1
240
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
Tell your own story through comics
letsgokoyo
1
1.1k
Transcript
0 分散型タスクスケジューリングシステム 2023-11-17 第68回NearMe技術勉強会 @yujiosaka
1
2 タスクスケジューリングの悩み 今決まった時間に実行している バッチ処理を、データベースに 登録された値に応じて、動的に タスクの実行間隔を制御したい タスクをスケジューリング するためだけにプロセスを 常駐させるのは面倒だし、 乗り換え作業も大掛かりだわ
3 やりたいことのイメージ const jobInterval = await dokkaKaraMottekuru(); // > “0
* * * *” — cron expression in string // > 1000 * 60 * 60 — milliseconds in number // > { “hours”: 1 } — date-fns Duration object // > etc. await schedule({ jobInterval }, async () => { }); await nannkaOmoiShori();
4 気をつけないといけないこと • どのタイミングでタスクの実⾏間隔(jobInterval)を更新するのか • どこにタスクの実⾏履歴を保存するのか • タスクをスケジューリングするためのプロセスを常駐させるのか → 最初に登録された実⾏間隔でタスクが実⾏され続けないようにしたい
→ プロセスを再起動した時に、実⾏間隔がリセットされないようにしたい → プロセスを常駐させるなら、そのプロセスをモニタリングしないといけない
5 node-cron https://github.com/kelektiv/node-cron 5
6 API cron.schedule(“0 * * * *”, () => {
nannkaOmoiShori(); })
7 やってること (概念的には)Cron Expressionをミリ秒に置き換えてsetIntervalを実⾏しているだけ (実際にはsetIntervalではなくてsetTimeoutを再起的に実⾏している) cron.schedule(“0 * * * *”,
() => { nannkaOmoiShori(); }) setInterval(() => { nannkaOmoiShori(); }, 1000 * 60 * 60);
8 嬉しいこと • 直感的に使えてシンプルなAPI • 依存関係がなく、インストールするだけですぐに使える 困ったこと • プロセスが再起動すると実⾏間隔がリセットされてしまう •
タスクの実⾏間隔(jobInterval)をいつ更新するべきかが悩ましい • プロセスを常駐させるため、タスクが実⾏されていない間のリソースが無駄 • プロセスの⽣存を常にモニタリングしなければならない • Cron型からプロセス常駐型への移⾏に⼿間が少しかかる
9 Agenda https://github.com/agenda/agenda 9
10 API const agenda = new Agenda({ db: { address:
process.env.MONGO_URI } }); await agenda.start(); // worker agenda.define(“nannka omoi shori”, async job => { await nannkaOmoiShori(); }); // scheduler await agenda.every(“0 * * * *”, “nannka omoi shori”);
11 やってること MongoDBをジョブキューとしてタスク処理を分散化 MongoDB Task Task Task Worker Worker Worker
Scheduler Task
12 嬉しいこと • 複数のプロセスでタスク処理を分散することができる • 並列度やタスクの優先度を細かく設定することができる • タスクスケジューリング以外にもキューとして使⽤できる 困ったこと •
スケジューラーが再起動するたびにスケジュールがリセットされてしまう • タスクの実⾏間隔(jobInterval)をいつ更新するべきかが悩ましい • スケジューラーは冗⻑化させることができず、モニタリングは相変わらず必要 • Cron型からキュー型への移⾏はとても⼤変 • MongoDB縛り(同様にbullはRedis縛り)
13 Cronのシンプルさとモダンなタスクスケジューラーの 柔軟性を持ち合わせたライブラリを作れないだろうか
14 Cronyx https://github.com/yujiosaka/Cronyx
15 API await cronyx.requestJobExec( { jobName: "hourly-job", jobInterval: "0 *
* * *", }, async (job) => { await nannkaOmoiShori(); }, );
16 やってること • 実際はタスクスケジューラーというよりタスクガードとして振る舞う • 直前のタスクの実⾏時間を保存し、条件を満たした時にだけタスクが実⾏される • 条件を満たしていない場合タスクを実⾏せず、すぐにPromiseをResolveする Database Lock
Lock Lock ロック要求 ロック要求
17 嬉しいこと • プロセスを常駐させる必要がないため、リソースが無駄にならずモニタリングも簡単 • タスクの実⾏間隔(jobInterval)の更新に強く、常に最新の設定が反映される • プロセスに障害が発⽣しても実⾏間隔がリセットされることがない • Cronを使い続けることができるので、乗り換えが楽
困ったこと • 「タスクスケジューラー」ではなく「タスクガード」なので、少し混乱するかも
18 その他の機能 • 依存関係の解決 • タスクの実⾏に遅延や障害が発⽣しても、⾃動で空⽩期間を埋めて復旧する • MongoDB、Redis、MySQL、Postgresの4つをデータソースとしてサポート • トランザクションやアトミックな処理等を使って安全なタスク分散を実現
• それ以外のデータソースも⾃分でプラグインを作成して利⽤できる
19 依存関係の解決 await cronyx.requestJobExec( { jobName: "child-job", jobInterval: "*/30 *
* * *", }, async (job) => { console.log(job.intervalStartedAt); console.log(job.intervalEndedAt); }, ); await cronyx.requestJobExec( { jobName: "parent-job", jobInterval: "0 * * * *", }, async (job) => { console.log(job.intervalStartedAt); console.log(job.intervalEndedAt); }, ); child-job.ts parent-job.ts requiredJobNames: ["child-job"],
20 その他の機能 • 依存関係の解決 • タスクの実⾏に遅延や障害が発⽣しても、⾃動で空⽩期間を埋めて復旧する • MongoDB、Redis、MySQL、Postgresの4つをデータソースとしてサポート • トランザクションやアトミックな処理等を使って安全なタスク分散を実現
• それ以外のデータソースも⾃分でプラグインを作成して利⽤できる
21 MongoDB export const mongodbJobLockSchema = new Schema({ jobName: {
type: String, required: true }, jobInterval: { type: Number, required: true, default: 0 }, jobIntervalEndedAt: { type: Date, required: true }, isActive: { type: Boolean, required: true, default: true }, createdAt: { type: Date, required: true, default: Date.now }, updatedAt: { type: Date, required: true, default: Date.now }, }).index({ jobName: 1, jobIntervalEndedAt: 1 }, { unique: true })
22 MongoDB try { return await this.#model.findOneAndUpdate( { jobName, jobIntervalEndedAt,
isActive: true }, { jobInterval, updatedAt: new Date() }, { setDefaultsOnInsert: true, new: true }, ); } catch (error) { throw error; } if (error instanceof MongoError && error.code === 11000) { return null; } , upsert: true
23 Cronからの移行手順 23
24 ステップ① cronyx.requestJobExecで元の処理を囲む await nannkaOmoiShori(); await cronyx.requestJobExec({ jobName: "job", jobInterval:
"0 * * * *", }, nannkaOmoisShori);
25 ステップ② Cronの実行時間をjobIntervalよりも短い間隔で設定する。 → こうすることで、遅延が発生しても自動で復旧できるようになる 0 * * * *
./nannka-omoi-shori.ts */10 * * * * ./nannka-omoi-shori.ts
26 これからやること • あらゆるサービスから利⽤できるように、HTTPサーバーを提供する • 様々な⾔語から利⽤できるように、クライアントを提供する やったこと
27 CronyxServer https://github.com/yujiosaka/CronyxServer
28 CronyxClient.js https://github.com/yujiosaka/CronyxClient.js
29 CronyxClient.py https://github.com/yujiosaka/CronyxClient.py
30 おまけ • CronyxServerはBun + Elysiaで実装 • その他のプロジェクトもNodeで動作するがBunファーストで開発(今度発表します)
31 解説記事 https://medium.com/@yujiisobe/cronyx-bridging-the-gap-between-cron-jobs-and-task-scheduling-790b9f709224
32 Thank you