Ccmmutty logo
Commutty IT
15 min read

Dart言語製のジョブスケジューリングフレームワークを開発しました

https://cdn.magicode.io/media/notebox/blob_bu20jTR

Batch.dart の紹介

Batch.dart
※ こちらの記事はZennからの転載です。

始めに

どうも、真也です。
ここ数年ほど Flutter ばかりが注目されている Dart言語 ですが、長寿命のサーバーサイド処理も十分すぎるほどこなせるパワフルな言語であることを証明するために、Dart VM 上で動作する Batch.dart というジョブスケジューリングフレームワークを開発しました。
この記事ではその Batch.dart の軽い紹介をしようと思います。

Batch.dart とはなにか

先に少し触れましたが、Batch.dartDart言語 で作成された包括的なジョブスケジューリングフレームワークです。ジョブをスケジューリングをする際に必要となる高性能な機能を標準で提供しており、そのどの機能もとても簡単に扱うことができるように設計されています。
よく知られているこの分野の先駆的な巨人は 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でのジョブスケジューリングを標準で提供しています。
  • フレームワークを実行するための複雑な処理や定義ファイルがありません
  • カスタマイズ可能なロギング機能を標準で提供しています。
  • 並列処理をサポートしています。
  • JobStep条件分岐をサポートしています。
  • 便利なコールバック関数が標準で多く提供されています。
  • 例外発生時のスキップ処理リトライ処理をサポートしています。
  • なにより、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 して動作確認していただくことも可能です。

検証時情報

バージョン
batchv1.3.0
Dart2.16.2

ライブラリのインストール

Dart言語 でお馴染みの以下のコマンドでライブラリのインストールが可能です。
dart pub add batch
dart pub get
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 分ごとに処理が実行されるようにスケジューリングしています。
そして、先に作成した SayHelloTaskSayWorldTaskStep として steps に指定します。
ここまでの手順でジョブのスケジューリングは完了です!

スケジュールされた Job を実行する処理を追加

最後にスケジュールされたジョブを実行する処理を追加する必要があります。
エントリーポイントとなる main メソッドに以下の処理を加えてください。runWorkflow メソッドが実行されると Batch.dart のライフサイクルが開始されます。
runWorkflow メソッドの jobs 引数には ScheduledJobBuilderimplements したクラスを渡してください。今回の例だと 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オープンソースですのでどのような方でも開発に貢献することができます。開発リポジトリの公用語は英語にしていますが、日本人の方々も大歓迎ですのでお気軽に IssuePull Request を作成してください。
また、IssuePull Request はハードルが高いがそれでも何か貢献したいという方は、GitHub の開発リポジトリにスターを付けることや、Pub.devいいねを付けることを検討してください。これは Batch.dart の開発コミュニティを活性化するためにとても大きな意味があります。

スポンサーの募集

今回紹介した Batch.dart に限った話ではありませんが、国内外を問わずオープンソース開発をサポートしてくださるスポンサーを募集しています。少額からの寄付も可能ですので、以下のリンクから是非ご支援ください。
また、この記事にバッジを贈っていただくことでも支援は可能です。

コミュニティの宣伝

Twitter には Flutter に関するトピックを扱うコミュニティはあるのですが、Dart言語 の全般的なトピックを扱うコミュニティは存在しなかったため私が作成しました。これは日本に限定したコミュニティではなく、全世界の Dartエンジニア に向けたコミュニティなので公用語は主に英語ですが、日本人の方々も大歓迎ですので少しでも興味のある方は加入をお願いします。

Discussion

コメントにはログインが必要です。