Batch.dart の紹介
※ こちらの記事はZennからの転載です。
始めに
どうも、真也です。
ここ数年ほど Flutter
ばかりが注目されている Dart言語
ですが、長寿命のサーバーサイド処理も十分すぎるほどこなせるパワフルな言語であることを証明するために、Dart VM
上で動作する Batch.dart というジョブスケジューリングフレームワークを開発しました。
この記事ではその Batch.dart の軽い紹介をしようと思います。
Batch.dart とはなにか
先に少し触れましたが、Batch.dart は Dart言語
で作成された包括的なジョブスケジューリングフレームワークです。ジョブをスケジューリングをする際に必要となる高性能な機能を標準で提供しており、そのどの機能もとても簡単に扱うことができるように設計されています。
よく知られているこの分野の先駆的な巨人は Java言語
の Spring Batch ですが、小さなバッチ処理をスケジューリングする際にも多くの定義や処理が必要となり、学習コストがとても高いフレームワークという印象があります。Spring Batch でジョブスケジューリングをしようとして、そもそも Spring の仕様を理解できずに挫折してしまった方も多いのではないかと思います。
その一方で、私が設計開発した Batch.dart ではジョブスケジューリングに関する一連の高性能な仕様は維持しつつ開発者の学習コストを極力なくすことに焦点を当てています。また、これは単なる言葉遊びではなく、実際に Batch.dart に触れていただければその直感的な操作性に気がついていただけるのではないかと思います。
それではもう少し Batch.dart の特徴を見ていきましょう。
Note:
Spring Batch について散々なことを書きましたが、私はもともと Javaエンジニア
であり Spring フレームワークや開発者の方々をとても尊敬しています。
Batch.dart で何ができるのか
Batch.dart は汎用的なジョブスケジューリングフレームワークであり、様々なユースケースに応えることができます。
全ての機能をこの記事一本で紹介することはできませんが、Batch.dart には主に以下の仕様があります。
- GitHub Actions のような形式のジョブスケジューリングをサポートしています。
- Cronでのジョブスケジューリングを標準で提供しています。
- フレームワークを実行するための複雑な処理や定義ファイルがありません。
- カスタマイズ可能なロギング機能を標準で提供しています。
- 並列処理をサポートしています。
Job
や Step
の条件分岐をサポートしています。
- 便利なコールバック関数が標準で多く提供されています。
- 例外発生時のスキップ処理やリトライ処理をサポートしています。
- なにより、Dart を使用してジョブスケジューリングができます。
- 等々...
基本コンセプト
Batch.dart のライフサイクルは以下の単位の集合で構成されています。
| 説明 |
---|
Job | 最も大きい単位であり、複数の Step を必ず持ち一連のバッチ処理を表現します。 |
Step | 中間的な単位であり、順列または並列のタスク処理を表現します。 |
Task | 最も小さい単位であり、バッチ処理における具体的な処理を表現します。 |
基本的なコンセプトは上記のとおりですが、実際に Batch.dart を使用して実装する際には次のコンセプトも重要になります。
- Job
- Job: スケジュール持たない
Job
です。条件分岐時に即時実行する場合に使用します。
- ScheduledJob: 必ずスケジュールを持つ
Job
です。Cron形式
でスケジューリングする際にはこの ScheduledJob
を使用します。
- Step
- Step: 順列処理を表現した
Step
で、一つの Task
を持ちます。
- ParallelStep: 並列処理を表現した
Step
で、複数の ParallelTask
を持ちます。
- Task
- Task: 順列処理での具体的なバッチ処理を表現します。
- ParallelTask: 並列処理での具体的なバッチ処理を表現します。
実際に Batch.dart を使用してみる
ここまでいろいろと書いてきましたが、実践に勝るものはないので実際に Batch.dart
を使用して Hello, World!
を出力する簡単なバッチアプリケーションを作成してみます。
また、ここから作成していくサンプルアプリの完成形は
ここにありますので、そのまま
clone
して動作確認していただくことも可能です。
検証時情報
| バージョン |
---|
batch | v1.3.0 |
Dart | 2.16.2 |
ライブラリのインストール
Dart言語
でお馴染みの以下のコマンドでライブラリのインストールが可能です。
Note:
Pub.dev ではこのライブラリが
Flutter
でも使用できると自動でラベリングされていますが、ご想像のとおり
Flutter
と併用はできませんのでご注意ください。
パッケージのインポート
以下の一文で Batch.dart を使用するための全ての機能をインポートすることができます。
import 'package:batch/batch.dart';
タスクの実装
まずは具体的なバッチ処理を表現する Task
を実装していきましょう。
Task
クラスを継承して execute
メソッドを実装してください。今回は同期処理のみを実装しますが、execute
メソッドの返却型を Future<void>
または FutureOr<void>
にすることで非同期処理も可能です。
上記の処理を見てお気づきの方もいるかもしれませんが、Batch.dart では標準でロギング機能が提供されているだけではなく明示的なロガーの初期化も不要です。Batch.dart で提供されるロガーはBatch.dart の処理が開始された際に安全かつ自動的にロードされます。
Job をスケジューリングする
Task
の実装が完了したら次は Job
をスケジューリングしていきましょう。
ScheduledJobBuilder
クラスを implements
して build
メソッドを実装してください。この build
メソッドで返却する型は先に紹介した ScheduledJob
です。
スケジュールは
CronParser
のコンストラクタに
Cron 形式の文字列を渡してください。例えば、以下の例では 2 分ごとに処理が実行されるようにスケジューリングしています。
そして、先に作成した SayHelloTask
と SayWorldTask
を Step
として steps
に指定します。
ここまでの手順でジョブのスケジューリングは完了です!
スケジュールされた Job を実行する処理を追加
最後にスケジュールされたジョブを実行する処理を追加する必要があります。
エントリーポイントとなる main
メソッドに以下の処理を加えてください。runWorkflow
メソッドが実行されると Batch.dart のライフサイクルが開始されます。
runWorkflow
メソッドの jobs
引数には ScheduledJobBuilder
を implements
したクラスを渡してください。今回の例だと SayHelloWorldJob
になります。
完成
ここまででアプリケーションを実行する際の必要最低限の実装が完了しました。以下が今回の例の全体像です。
また、以下が今回の例の実行結果になります。
2022-04-24 10:09:07.678 [info ] (_BannerPrinter.execute:25:39 ) -
╔═════════════════════════════════════════════════════════════════════════╗
║ ║
║ ╭━━╮╱╱╱╭╮╱╱╱╭╮╱╱╱╱╭╮╱╱╱╱╭╮ ║
║ ┃╭╮┃╱╱╭╯╰╮╱╱┃┃╱╱╱╱┃┃╱╱╱╭╯╰╮ ║
║ ┃╰╯╰┳━┻╮╭╋━━┫╰━╮╭━╯┣━━┳┻╮╭╯ ║
║ ┃╭━╮┃╭╮┃┃┃╭━┫╭╮┃┃╭╮┃╭╮┃╭┫┃ ║
║ ┃╰━╯┃╭╮┃╰┫╰━┫┃┃┣┫╰╯┃╭╮┃┃┃╰╮ ║
║ ╰━━━┻╯╰┻━┻━━┻╯╰┻┻━━┻╯╰┻╯╰━╯ ║
║ ╱╱╭╮╱╱╭╮╱╱╭━━━╮╱╱╭╮╱╱╱╱╱╱╭╮╱╱╭╮╱╱╱╱╱╱╱╱╭━━━╮╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╭╮ ║
║ ╱╱┃┃╱╱┃┃╱╱┃╭━╮┃╱╱┃┃╱╱╱╱╱╱┃┃╱╱┃┃╱╱╱╱╱╱╱╱┃╭━━╯╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱┃┃ ║
║ ╱╱┃┣━━┫╰━╮┃╰━━┳━━┫╰━┳━━┳━╯┣╮╭┫┃╭┳━╮╭━━╮┃╰━━┳━┳━━┳╮╭┳━━┳╮╭╮╭┳━━┳━┫┃╭╮ ║
║ ╭╮┃┃╭╮┃╭╮┃╰━━╮┃╭━┫╭╮┃┃━┫╭╮┃┃┃┃┃┣┫╭╮┫╭╮┃┃╭━━┫╭┫╭╮┃╰╯┃┃━┫╰╯╰╯┃╭╮┃╭┫╰╯╯ ║
║ ┃╰╯┃╰╯┃╰╯┃┃╰━╯┃╰━┫┃┃┃┃━┫╰╯┃╰╯┃╰┫┃┃┃┃╰╯┃┃┃╱╱┃┃┃╭╮┃┃┃┃┃━╋╮╭╮╭┫╰╯┃┃┃╭╮╮ ║
║ ╰━━┻━━┻━━╯╰━━━┻━━┻╯╰┻━━┻━━┻━━┻━┻┻╯╰┻━╮┃╰╯╱╱╰╯╰╯╰┻┻┻┻━━╯╰╯╰╯╰━━┻╯╰╯╰╯ ║
║ ╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╭━╯┃ ║
║ ╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╰━━╯ ║
║ ║
╠═════════════════════════════════════════════════════════════════════════╣
║ Version : 1.3.0 ║
║ License : BSD 3-Clause ║
║ Author : Kato Shinya (https://github.com/myConsciousness) ║
╚═════════════════════════════════════════════════════════════════════════╝
2022-04-24 10:09:08.229 [info ] (_BatchApplication.run:157:11 ) - 🚀🚀🚀🚀🚀🚀🚀 The batch process has started! 🚀🚀🚀🚀🚀🚀🚀
2022-04-24 10:09:08.232 [info ] (_BatchApplication.run:158:11 ) - Logger instance has completed loading
2022-04-24 10:09:08.234 [info ] (_BootDiagnostics.execute:36:9 ) - Batch application diagnostics have been started
2022-04-24 10:09:08.239 [info ] (_BootDiagnostics.execute:50:9 ) - Batch application diagnostics have been completed
2022-04-24 10:09:08.239 [info ] (_BootDiagnostics.execute:51:9 ) - Batch applications can be started securely
2022-04-24 10:09:08.240 [info ] (JobScheduler.run:36:9 ) - Started Job scheduling on startup
2022-04-24 10:09:08.240 [info ] (JobScheduler.run:37:9 ) - Detected 1 Jobs on the root
2022-04-24 10:09:08.240 [info ] (JobScheduler.run:40:11 ) - Scheduling Job [name=Say Hello World Job]
2022-04-24 10:09:08.250 [info ] (JobScheduler.run:55:9 ) - Job scheduling has been completed and the batch application is now running
2022-04-24 10:10:00.041 [info ] (upport.startNewExecution:37:11) - Job: [name=Say Hello World Job] launched with the following shared parameters: {}
2022-04-24 10:10:00.052 [info ] (upport.startNewExecution:41:11) - Step: [name=Say Hello Step] launched with the following job parameters: {}
2022-04-24 10:10:00.054 [info ] (SayHelloTask.execute:22:9 ) - Hello,
2022-04-24 10:10:00.057 [info ] (Support._finishExecution:72:11) - Step: [name=Say Hello Step] finished with the following job parameters: {} and the status: [completed]
2022-04-24 10:10:00.058 [info ] (upport.startNewExecution:41:11) - Step: [name=Say World Step] launched with the following job parameters: {}
2022-04-24 10:10:00.059 [info ] (SayWorldTask.execute:29:9 ) - World!
2022-04-24 10:10:00.060 [info ] (Support._finishExecution:72:11) - Step: [name=Say World Step] finished with the following job parameters: {} and the status: [completed]
2022-04-24 10:10:00.061 [info ] (Support._finishExecution:68:11) - Job: [name=Say Hello World Job] finished with the following shared parameters: {} and the status: [completed]
その他の実装例
以下のリンクでユースケースごとの実装例を掲載していますので参考にしてください。
または、
こちらでより多くの例を参照することができます。
貢献者の募集
Batch.dart はオープンソースですのでどのような方でも開発に貢献することができます。開発リポジトリの公用語は英語にしていますが、日本人の方々も大歓迎ですのでお気軽に Issue
や Pull Request
を作成してください。
また、Issue
や Pull Request
はハードルが高いがそれでも何か貢献したいという方は、GitHub
の開発リポジトリにスターを付けることや、Pub.dev
のいいねを付けることを検討してください。これは Batch.dart の開発コミュニティを活性化するためにとても大きな意味があります。
スポンサーの募集
今回紹介した Batch.dart に限った話ではありませんが、国内外を問わずオープンソース開発をサポートしてくださるスポンサーを募集しています。少額からの寄付も可能ですので、以下のリンクから是非ご支援ください。
また、この記事にバッジを贈っていただくことでも支援は可能です。
コミュニティの宣伝
Twitter
には Flutter
に関するトピックを扱うコミュニティはあるのですが、Dart言語
の全般的なトピックを扱うコミュニティは存在しなかったため私が作成しました。これは日本に限定したコミュニティではなく、全世界の Dartエンジニア
に向けたコミュニティなので公用語は主に英語ですが、日本人の方々も大歓迎ですので少しでも興味のある方は加入をお願いします。