背景と適用シナリオ
Salesforce 開発者として、私たちは日々の業務で様々なビジネスプロセスの自動化要件に直面します。レコードの作成や更新をトリガーとする Apex Trigger や、ユーザーのアクションを起点とするフロー(Flow)は強力なツールですが、特定の時間に、あるいは定期的に実行したいタスクには対応できません。例えば、「毎晩深夜に外部システムからデータを同期する」「毎週月曜日の朝に全営業担当者へ今週の活動レポートをメールで送信する」「毎月末に売上実績を集計し、カスタムオブジェクトに保存する」といった要件です。
このような時間ベースの自動化を実現するために Salesforce Platform が提供する強力な機能が Schedulable Apex です。Schedulable Apex を利用することで、開発者は Apex クラスを特定の日時に実行するようにスケジュール設定できます。これにより、手動での介入を必要とせず、定期的かつ確実にビジネスロジックを実行することが可能になります。この記事では、Salesforce 開発者の視点から Schedulable Apex の原理を深く掘り下げ、具体的な実装方法、注意点、そしてベストプラクティスについて詳しく解説します。
原理説明
Schedulable Apex の中核をなすのは、Salesforce が提供する Schedulable
interface(インターフェース)です。このインターフェースを Apex クラスに実装(implement)することで、そのクラスをスケジューリング可能なジョブとして Salesforce プラットフォームに認識させることができます。
Schedulable
インターフェースには、実装が必須となるメソッドが一つだけ定義されています。
global void execute(SchedulableContext sc)
この execute
メソッドこそが、スケジュールされた時間に実行される処理ロジックの本体です。パラメータとして渡される SchedulableContext
オブジェクトは、現在実行中のジョブに関する情報(例えば、ジョブのトリガー ID など)を取得するために使用できます。
作成した Schedulable Apex クラスをスケジュールする方法は主に2つあります。
1. Salesforce UI を使用する方法
[設定] > [Apex クラス] > [Apex をスケジュール] ボタンから、GUI を通じてジョブ名、対象の Apex クラス、実行頻度(毎週、毎月など)、開始・終了日、希望時間を設定できます。この方法は、コーディングを必要とせず、システム管理者が手軽にジョブをスケジュールしたい場合に便利です。
2. System.schedule メソッドを使用する方法
開発者にとってより柔軟で強力な方法が、Apex コードから System.schedule
メソッドを呼び出すことです。このメソッドは、開発者コンソールの匿名実行(Anonymous Execution)ウィンドウや、別の Apex クラス内から実行できます。
System.schedule(jobName, cronExpression, schedulableClass)
このメソッドは3つの引数を取ります。
- jobName (String): スケジュールされたジョブの一意な名前です。[設定] の [スケジュール済みジョブ] ページでこの名前が表示されます。
- cronExpression (String): ジョブをいつ実行するかを定義する Cron Expression(クロン式)です。非常に柔軟なスケジュール設定が可能です。
- schedulableClass (Object): スケジュールしたい
Schedulable
インターフェースを実装したクラスのインスタンスです。
特に重要なのが Cron Expression です。これは7つのスペース区切りの値で構成され、それぞれが「秒、分、時、日、月、曜日、年(任意)」を表します。例えば、'0 0 22 ? * MON-FRI'
は「月曜日から金曜日の毎日、午後10時0分0秒に実行」を意味します。この表現をマスターすることが、Schedulable Apex を使いこなす鍵となります。
サンプルコード
Schedulable Apex の execute
メソッドは、それ自体が非同期処理のコンテキストで実行されますが、一度のトランザクションで処理できるレコード数には Governor Limits(ガバナ制限)が存在します。そのため、大量のデータを処理する場合には、execute
メソッドから直接処理を行うのではなく、Batch Apex(バッチ Apex)を呼び出すのがベストプラクティスです。
以下に、毎日特定の時間に Batch Apex を起動する Schedulable Apex クラスの公式ドキュメントに基づくサンプルコードを示します。
1. 処理対象の Batch Apex クラス
まず、実際にデータ処理を行うバッチクラスを準備します。この例では、すべてのアカウントレコードをクエリし、各アカウントの説明(Description)項目を更新します。
global class DailyAccountBatch implements Database.Batchable<sObject> { // バッチジョブの開始時にコールされるメソッド // 処理対象のレコードを返す SOQL クエリを定義します global Database.QueryLocator start(Database.BatchableContext bc) { return Database.getQueryLocator('SELECT Id, Description FROM Account'); } // start メソッドで取得したレコードのチャンク(塊)ごとにコールされるメソッド // ここに実際のビジネスロジックを記述します global void execute(Database.BatchableContext bc, List<Account> scope) { List<Account> accountsToUpdate = new List<Account>(); for (Account acc : scope) { // 既存の説明に更新日時を追記 String currentDescription = acc.Description == null ? '' : acc.Description; acc.Description = currentDescription + ' Updated by Batch on ' + System.now(); accountsToUpdate.add(acc); } // DML 操作は一度にまとめて実行する if (!accountsToUpdate.isEmpty()) { update accountsToUpdate; } } // すべてのチャンクの処理が完了した後にコールされるメソッド // ジョブの完了通知などに使用します global void finish(Database.BatchableContext bc) { // 例: ジョブ完了をメールで通知する System.debug('DailyAccountBatch job finished successfully.'); } }
2. Batch Apex を呼び出す Schedulable Apex クラス
次に、上記のバッチクラスをスケジュールに従って起動するための Schedulable クラスを作成します。
global class ScheduledBatchable implements Schedulable { // スケジュールされた時間にこの execute メソッドが実行されます global void execute(SchedulableContext sc) { // 処理対象のバッチクラスのインスタンスを生成 DailyAccountBatch batchJob = new DailyAccountBatch(); // Database.executeBatch を呼び出してバッチジョブを開始 // 第2引数はチャンクサイズ(1回の execute で処理するレコード数) // 省略するとデフォルトの200が使用されます Database.executeBatch(batchJob, 200); } }
3. ジョブのスケジュール実行
最後に、開発者コンソールの「Debug」>「Open Execute Anonymous Window」を開き、以下のコードを実行してジョブをスケジュールします。この例では、毎日午前3時にジョブが実行されるように設定します。
// スケジュールするクラスのインスタンスを作成 ScheduledBatchable scheduler = new ScheduledBatchable(); // Cron 式を定義(秒 分 時 日 月 曜日) // '0 0 3 * * ?' は「毎日午前3時0分0秒」を意味します String cronExpression = '0 0 3 * * ?'; // ジョブ名、Cron 式、クラスインスタンスを指定してジョブをスケジュール String jobID = System.schedule('Daily Account Update Batch', cronExpression, scheduler); // スケジュールされたジョブの ID をデバッグログに出力 System.debug('Scheduled job ID: ' + jobID);
注意事項
Schedulable Apex は非常に便利ですが、開発者として留意すべき点がいくつかあります。
ガバナ制限 (Governor Limits)
Schedulable Apex は非同期処理ですが、同期処理と同様のガバナ制限(SOQLクエリ発行回数100回、合計ヒープサイズ6MBなど)が適用されます。これが、大量データを扱う際に Batch Apex を呼び出すことが推奨される最大の理由です。Batch Apex は独自のガバナ制限セットを持ち、はるかに大きなデータ量を安全に処理できます。
ジョブ数の制限
Salesforce 組織で同時に有効にできるスケジュール済み Apex ジョブの数には上限があります(通常は100件)。設計時には、組織全体のジョブ数を考慮し、不必要にジョブを分割しないように注意が必要です。CronTrigger
オブジェクトを SOQL でクエリすることで、現在スケジュールされているジョブの一覧を確認できます。
権限と実行コンテキスト
スケジュールされたジョブは、そのジョブをスケジュールしたユーザーのコンテキストで実行されます。これは、そのユーザーのプロファイルと権限セットが、ジョブ内で実行される SOQL クエリの可視性や DML 操作の可否に直接影響することを意味します。意図しないデータアクセスや権限エラーを防ぐため、十分な権限を持つ専用のインテグレーションユーザーでジョブをスケジュールすることが推奨されます。
エラー処理と監視
ジョブはバックグラウンドで実行されるため、例外が発生してもユーザーには直接通知されません。堅牢なエラー処理メカニズムを実装することが不可欠です。try-catch
ブロックを使用して例外を捕捉し、エラー内容をカスタムオブジェクトに記録したり、Messaging.SingleEmailMessage
を使用してシステム管理者に通知したりする仕組みを組み込みましょう。また、[設定] > [ジョブ] > [Apex ジョブ] ページでジョブの実行状況(成功、失敗)を定期的に監視することも重要です。
テストクラスの実装
Schedulable Apex も他の Apex コードと同様に、75% 以上のコードカバレッジを持つテストクラスが必須です。テストクラス内では、Test.startTest()
と Test.stopTest()
を使用して非同期処理をテストします。System.schedule
は Test.startTest()
と Test.stopTest()
のブロック内でコールします。Test.stopTest()
が実行されると、スケジュールされたジョブは同期的に即時実行されるため、その結果を System.assertEquals()
などで検証することができます。
まとめとベストプラクティス
Schedulable Apex は、Salesforce プラットフォームにおける時間ベースの自動化を実現するための不可欠なツールです。定期的なデータクレンジング、レポート作成、システム連携など、その活用範囲は多岐にわたります。開発者としてこの機能を最大限に活用するためには、以下のベストプラクティスを遵守することが重要です。
- ロジックの分離: Schedulable クラスの
execute
メソッドは、ジョブを起動する役割に徹し、実際の複雑なビジネスロジックは別のクラス(ヘルパークラスや Batch Apex クラス)に実装します。これにより、コードの再利用性と保守性が向上します。 - 大量データは Batch Apex で: 100件を超えるようなレコードを処理する可能性がある場合は、必ず Batch Apex を呼び出してください。これにより、ガバナ制限を回避し、安定した処理を実現できます。
- 設定の外部化: スケジュール時間(Cron Expression)や処理の閾値などの設定値を、コード内にハードコーディングするのではなく、カスタムメタデータ型(Custom Metadata Types)やカスタム設定(Custom Settings)に格納します。これにより、コードを修正・デプロイすることなく、システム管理者が設定を柔軟に変更できます。
- 堅牢なエラーハンドリング: 必ず
try-catch
ブロックを実装し、エラー発生時には詳細な情報をログとして記録し、関係者に通知する仕組みを構築します。誰にも気づかれないままジョブが失敗し続ける事態を避けましょう。 - 一貫性のある命名規則: スケジュールするジョブには、その目的が明確にわかるような一貫した命名規則(例: 「[機能名] [頻度] [処理内容]」)を適用します。[スケジュール済みジョブ] の一覧画面での可読性が向上します。
これらの原理とベストプラクティスを理解し、適切に実装することで、Schedulable Apex はあなたの Salesforce 開発における強力な武器となるでしょう。
コメント
コメントを投稿