Apexスケジュールの管理画面を作ってみました

こんにちは、戸塚です。

最近は連携案件を担当することが多かった為、画面開発についていろいろと忘れていることが多く、ちょいと危機感を覚えたので復習したかったのと、前から検証してみたい事があったので、この間1つ画面を作成してみました。

そして、私が所属するチームの課題発表でその画面を紹介したところ、意外にもニーズがありそうでしたので、今回のエントリはその時作成した画面「Apexスケジュールの管理画面」についてご紹介したいと思います。

こんな画面です

下の画面が今回作成したものです。

Apexスケジュール管理画面(全体)

画面上部でスケジュールの追加を行い、画面下部で登録されたスケジュールを一覧表示する画面となります。

できること

シンプルな画面ですので、主な機能としては下記3つのみとなります。

  1. スケジュールの追加
  2. スケジュールの一覧表示
  3. スケジュールの削除

標準機能と何が違うの?

上記の3機能はSalesforce標準の画面でも用意されている機能ですから、同じものを作成したのではつまらないのでいくつかの改良を加えたのと、個人的に必要ないかなと思う部分を切り捨てちゃいました。

また、Salesforceの仕様上どうしても実装不可能な部分もあったりもしたので、標準の管理画面と相違していそうな部分を下記にまとめてみました。

標準の管理画面 今回作成した画面
起動時間の分指定 不可 可能
毎時起動の指定 不可 可能
スケジュールの一括削除 不可 可能
起動開始日付の指定 可能 実装不可?
起動終了日付の指定 可能 実装不可?
毎月特定日のみ実行 可能 未実装
毎月特定週の特定曜日のみ実行 可能 未実装

実際に画面を触ってみます

例として、月曜から金曜まで毎時15分に「ScheduleClass」が実行されるようにスケジュールを登録してみます。

下記のように画面上部でスケジュール名、実行クラス、実行曜日、実行時間を選択して「追加」ボタンを押下します。

スケジュール登録画面

正常に処理が完了しますと、画面下部の一覧に登録したスケジュールが追加されます。

一覧画面(スケジュール登録後)

正常にスケジュールが登録されたようです。

では、上記画面で登録したスケジュールが、標準の管理画面ではどのように表示されるか見てみます。

標準の管理画面

標準の管理画面の「次の実行スケジュール」にも同様のスケジュールが追加されていますので問題なく登録されていることが分かります。

ただ1つ気になるのが、先程登録したスケジュールには何故か「Manage」リンクがついておりません。 「夜間バッチ1」というスケジュールも、今回作成した画面から登録したスケジュールですが、「Manage」リンクは表示されておりますので、「夜間バッチ3」というスケジュールが何かしらの条件を満たしていないのかもしれません。


次に、「夜間バッチ」と名のつく全スケジュールを一括で削除してみます。 画面下部の一覧画面で削除するスケジュールにチェックを入れ「削除」ボタンを押下します。

一覧画面(削除前)

正常に処理が完了しますと、下記のように画面下部の一覧から削除したスケジュールが表示されなくなります。

一覧画面(削除後)

念のため、標準の管理画面で本当に削除されたか確認してみます。

標準の管理画面の一覧(削除後)

「夜間バッチ」と名のつくスケジュールは表示されておりませんので、スケジュールの削除が成功しているのが確認できます。

実装上のポイント

それでは、今回の画面の実装内容や、実装する上で気付いた事等を説明致します。

「Schedulableインターフェイスを実装したクラスの特定」

実行可能クラスの選択リスト

スケジュール登録の際に、実行するクラスを選択する赤枠部分の選択リストですが、選択値は画面表示時にApexのコントローラで生成しています。

「ApexClass」という標準オブジェクトにクラスのデータが格納されているので、「Schedulable」インターフェイスを実装したクラスには「Schedule」という文字列が含まれている、という前提でクラス名を取得しています。

しかし、クラス名の部分一致という微妙な抽出方法なので、試しに全クラスの名前を取得した後クラス名からインスタンスを生成し、「instanceof」を使用して「Schedulable」インターフェイスを実装しているかどうか判定してみたところ、問題なく判定ができました。

ただ、処理スピードが気になっていたので必要情報をログに出力して検証していたところ、「newInstance()」を実行後に何故かQueryの実行回数が増加している事が分かりました。

「newInstance()」を実行した際に内部で実際にQueryを発行しているのかとも考えたのですが、実行の度に増加しているわけではないので、リフレクションの多用を制限する為に一定回数実行した場合にQuery回数を増加させるような仕様になっているのでしょうか・・・ 上記についてはSalesforce社に問い合わせてみようと思います。

「CronTriggerのラッパーオブジェクト」 ラッパーオブジェクトという表現が適切かどうかはさておき、今回の画面を作成するにあたり、「CustomCronTrigger」というカスタムオブジェクトを追加しています。

CustomCronTrigger

最初は「CronTrigger」のみで問題ないかと思っていたのですが、「CronTrigger」を検索する際にスケジュール名や実行クラス名が取得できないので、スケジュールを一覧表示した場合に何のスケジュールなのかぱっと見よくわかりませんでした。

そのため、カスタムオブジェクト「CustomCronTrigger」でスケジュール名や実行クラス名を保持するようにしました。

そして「スケジュールId」に「CronTrigger」のIdを保持することで「CustomCronTrigger」と「CronTrigger」の関連を擬似的に持たせ、プログラムの中でそれぞれのオブジェクトから必要な情報を抽出&結合してスケジュールの情報を一覧表示するよう実装しています。

また、カスタムオブジェクトを追加したことにより、実行結果の保持も容易になりそうです。 「CustomCronTrigger」を親とする「実行結果」のようなカスタムオブジェクトを作成し、スケジュール実行された処理の任意のタイミングで詳細な情報を当該オブジェクトに登録したりすることで、開発や運用フェーズでの実行結果の確認作業がしやすくなるかもしれません。

※ちなみにApexのクラス名や実行結果については、「Apex ジョブ」という標準の画面でも確認することができます。

「スケジュールの追加」

スケジュールを追加する部分ですが、リフレクションで実行クラスのインスタンスを生成している点を除いて、通常Apexでスケジュールを登録する方法と同様です。 詳しくはこちらをご参照ください。

「スケジュールの削除」

スケジュールを削除する部分も、通常Apexでスケジュールを削除する方法と同様です。 削除する際に使用するIdは「CustomCronTrigger」に保持していますので、「System.abortJob」の引数にそのIdを渡しています。

さいごに

今回は、標準で用意されているものを拡張したような画面を紹介致しました。 ユーザ向けの画面ではなく、開発をしている方やシステム管理者の方向けの画面になります。 いくつか制限がありますが、標準で用意されているものよりも使い勝手のよい画面にはなっていると思います。

ですが、標準の管理画面で分指定や毎時指定なんかができるようになってしまえば特に必要ないものです。 また、そもそもこんな画面などなくても現状は運用で何とかカバーできていることだと思います。

そしてこのような画面を作成した場合、Salesforceの内部仕様が変更されるとその影響を受けて動作しなくなるリスクがあり、開発する側としては今後の動作を保障できないので、こんな画面を作らずにすむよう標準の機能がもっともっと使いやすくなるといいですね。