Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
分散型タスクスケジューリングシステム
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
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の技術発表資料です
PosthogのA/Bテスト機能の紹介
nearme_tech
PRO
1
21
AIフレンドリーなプロダクトに向けて
nearme_tech
PRO
1
50
初めてのLean言語
nearme_tech
PRO
0
76
Apache Airflow Workflow orchestration without turning cron into spaghetti
nearme_tech
PRO
1
21
実務で役立つ幾何学 ボロノイ図の基礎から グラフ・ネットワーク応用まで
nearme_tech
PRO
1
59
SQL/ID抽出タスクから考える 実践的なハルシネーション対策
nearme_tech
PRO
1
67
OpenCode & Local LLM
nearme_tech
PRO
0
200
OpenCode Introduction
nearme_tech
PRO
0
59
【Browser Automation × AI】 Stagehandを試してみよう
nearme_tech
PRO
0
160
Other Decks in Programming
See All in Programming
Welcome to the "Parametricity" 🏙️ − Generic だけど Specific な世界 −
guvalif
PRO
1
180
任せる範囲はこう広がった / How the Scope of AI Delegation Has Expanded
nrslib
1
270
GitHubCopilotCLIのスラッシュコマンドを自作してみる
htkym
0
100
生成AI導入の「期待外れ」を乗り越える ー 開発フロー改革が目指す、真の組織変革
starfish719
0
2.1k
JAWS-UG横浜 #102 AWSサ終供養LT会 成仏できない AWS サービスたち 〜本日、三体供養します〜
maroon1st
0
240
変わらないものが、変わるものを決める — 意図駆動開発 × イベントソーシング × イミュータブル | What Doesn't Change Decides What Can — IDD × Event Sourcing × Immutability
tomohisa
0
250
数百円から始めるRuby電子工作
tarosay
0
100
吝嗇家のためのAI活用 / AI development for miser - ChatGPT + Issue Driven Development
tooppoo
0
190
『コードを書く以外の』エンジニアリング〜課金基盤移行プロジェクト推進のためのTips4選
yuriko1211
0
540
エンジニアにデザインハーネスを 〜デザインプロセスを規定するためのハーネス〜 / Design harness from an engineer's perspective
rkaga
2
1.7k
鹿野さんに聞く!『TypeScriptコードレシピ集』で磨く実践力
tonkotsuboy_com
4
1.2k
これからAgentCoreを触る方へトレンドはGatewayです
har1101
6
500
Featured
See All Featured
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
260
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
72
40k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
240
Large-scale JavaScript Application Architecture
addyosmani
515
110k
Product Roadmaps are Hard
iamctodd
55
12k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
410
Designing for humans not robots
tammielis
254
26k
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
330
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.7k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
201
75k
Balancing Empowerment & Direction
lara
6
1.2k
Design in an AI World
tapps
1
270
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