SalesforceのSchedulable Apexをマスターする:開発者向け自動化ガイド

背景と応用シナリオ

Salesforceプラットフォームにおいて、ビジネスプロセスの自動化は生産性向上の鍵となります。フロー (Flow) や承認プロセス (Approval Process) といった宣言的なツールで多くの要件を満たせますが、特定の時間に複雑なロジックを実行する必要がある場合、プログラムによるアプローチが不可欠です。ここで登場するのが Schedulable Apex (スケジュール可能なApex) です。

Schedulable Apexは、Apexクラスを特定の日時に、あるいは定期的に(例えば、毎日深夜、毎週月曜の朝など)実行するための強力な機能です。これにより、手動介入なしでバックグラウンド処理を自動化できます。

主な応用シナリオ

  • 夜間バッチ処理: 毎晩、その日に作成された全レコードをチェックし、データのクレンジングや更新、集計を行う。
  • 定期的なレポート生成と通知: 毎週金曜日の夕方に、その週の営業成績を集計し、サマリーレポートをマネージャーにメールで送信する。
  • 外部システムとのデータ同期: 1時間ごとに外部のERPシステムにAPIコールを行い、在庫情報をSalesforceの製品データと同期させる。
  • 期限切れレコードの管理: 毎日、契約終了日が近づいている契約レコードを検索し、担当者へのToDoを自動作成する。
  • データのアーカイブ: 月末に、3年以上前の活動履歴やケースレコードを抽出し、外部のストレージシステムにアーカイブ(移動)する。

これらのシナリオに共通するのは、「決まった時間に」「大量のデータを」「ユーザーの操作とは無関係に」処理する必要があるという点です。Schedulable Apexは、このような要求に応えるための、Salesforce開発者にとって必須のツールと言えるでしょう。


原理説明

Schedulable Apexの仕組みは、Salesforceが提供する特定のインターフェースを実装することで成り立っています。

1. System.Schedulable インターフェース

あるApexクラスをスケジュール可能にするには、そのクラスが `System.Schedulable` インターフェースを実装 (implement) する必要があります。このインターフェースには、実装が必須なメソッドが一つだけ定義されています。

`void execute(SchedulableContext sc)`

この `execute` メソッドが、スケジュールされた時間にSalesforceによって呼び出される処理の本体です。すべてのビジネスロジックは、このメソッド内に記述するか、ここから呼び出される別のメソッドに実装します。引数として渡される `SchedulableContext` オブジェクトは、現在実行中のスケジュール済みジョブのID(CronTrigger ID)などを取得するために使用できます。

2. ジョブのスケジューリング

`Schedulable` インターフェースを実装したクラスを作成しただけでは、自動実行はされません。そのクラスをいつ実行するかをSalesforceに登録する必要があります。この登録処理は、`System.schedule` メソッドを使用して行います。このメソッドは、通常、開発者コンソールの匿名実行ウィンドウ (Anonymous Window) や、別のApexクラスから一度だけ実行されます。

最も一般的に使用される `System.schedule` メソッドのシグネチャは以下の通りです。

`System.schedule(jobName, cronExpression, schedulableClassInstance)`

  • `jobName` (String): ジョブの名前です。 [設定] > [Apexジョブ] の一覧で表示されるため、一意で分かりやすい名前を付けます。
  • `cronExpression` (String): CRON式(クロンしき)と呼ばれる、ジョブの実行スケジュールを定義する文字列です。後述しますが、「秒 分 時 日 月 曜日」の形式で指定します。
  • `schedulableClassInstance` (Object): スケジュールしたいクラスのインスタンスを渡します。`new MySchedulableClass()` のように記述します。

CRON式は非常に柔軟で、「毎時0分」「毎週月曜の午前3時」「毎月1日の深夜0時15分」といった複雑なスケジュールを表現できます。

3. ジョブの監視

スケジュールされたジョブは、SalesforceのUIから監視できます。

  • スケジュール済みジョブ (Scheduled Jobs): [設定] > [スケジュール済みジョブ] で、今後実行が予定されているジョブの一覧を確認できます。ここからジョブの削除も可能です。
  • Apexジョブ (Apex Jobs): [設定] > [Apexジョブ] で、過去に実行されたジョブ、現在実行中のジョブ、そして未来のスケジュール済みジョブの実行結果(成功、失敗)やステータスを確認できます。エラーが発生した場合は、ここで詳細を調査します。

この「インターフェースの実装」「`System.schedule`による登録」「UIでの監視」という3つのステップが、Schedulable Apexの基本的な仕組みです。


示例代码

ここでは、Salesforce公式ドキュメントに記載されている例を基に、毎週特定の処理を実行するシンプルなSchedulable Apexクラスを作成し、それをスケジュールする方法を解説します。

1. Schedulable Apex クラスの作成

以下のコードは、`Schedulable` インターフェースを実装したクラスの例です。この例では、`execute` メソッド内で、後続の処理としてバッチApexを呼び出しています。これは、大量のデータを扱う際のベストプラクティスです。

// public class ScheduledBatchable implements Schedulable {
//     public void execute(SchedulableContext sc) {
//         // ここでバッチApexクラスのインスタンスを作成
//         MyBatchableClass b = new MyBatchableClass(); 
//         // バッチジョブを開始
//         Database.executeBatch(b);
//     }
// }

// 上記は概念的な例ですが、より具体的な公式ドキュメントの例を以下に示します。
// 毎週レポートを実行するというシナリオのクラスです。

global class WeeklyReport implements Schedulable {

    // executeメソッド。スケジュールされた時間にSalesforceがこのメソッドを呼び出します。
    global void execute(SchedulableContext sc) {
        // ここに毎週実行したいビジネスロジックを記述します。
        // 例えば、先週作成された取引先を取得します。
        List<Account> accounts = [SELECT Id, Name, CreatedDate FROM Account WHERE CreatedDate = LAST_WEEK];

        // 取得した取引先に対して何らかの処理を実行します。
        // 注意:大量のデータを処理する場合、このexecuteメソッド内で直接ループ処理を行うと
        // ガバナ制限に抵触する可能性があるため、バッチApexを呼び出すのが一般的です。
        // この例では簡潔にするため、直接処理を記述しています。
        for (Account acc : accounts) {
            // 例:取引先名に接尾辞を追加して更新する(あくまでサンプルです)
            acc.Name = acc.Name + ' (Weekly Check)';
        }

        // DML操作にはガバナ制限があるため、try-catchブロックでエラー処理を行うことが推奨されます。
        try {
            if (!accounts.isEmpty()) {
                update accounts;
            }
        } catch (DmlException e) {
            // エラーハンドリング:カスタムオブジェクトへのログ記録や、システム管理者へのメール通知など
            System.debug('An error occurred during the scheduled job: ' + e.getMessage());
        }
    }
}

2. ジョブのスケジュール実行

上記の `WeeklyReport` クラスをスケジュールするには、開発者コンソールの [Debug] > [Open Execute Anonymous Window] を開き、以下のコードを実行します。

// WeeklyReportクラスのインスタンスを作成します。
WeeklyReport weeklyReportJob = new WeeklyReport();

// CRON式を定義します。
// 形式: '秒 分 時 日 月 曜日'
// この例では '0 0 1 ? * MON' となり、
// 毎週月曜日の午前1時にジョブを実行することを意味します。
//
// CRON式の各フィールドの説明:
// 1. 秒 (0-59)
// 2. 分 (0-59)
// 3. 時 (0-23)
// 4. 日 (1-31) - '?' は「指定なし」を意味します。日と曜日のどちらかには'?'を使います。
// 5. 月 (1-12 or JAN-DEC) - '*' は「毎月」を意味します。
// 6. 曜日 (1-7 or SUN-SAT) - 'MON'は月曜日を意味します。
// 7. (オプション) 年 (1970-2099)
String cronExpression = '0 0 1 ? * MON';

// ジョブの名前、CRON式、クラスのインスタンスを渡してスケジュールします。
// ジョブ名は組織内で一意である必要があります。
String jobName = 'Weekly Account Report Job';
System.schedule(jobName, cronExpression, weeklyReportJob);

このコードを実行すると、`Weekly Account Report Job` という名前のジョブがシステムに登録され、以後、毎週月曜の午前1時に自動的に `WeeklyReport` クラスの `execute` メソッドが実行されるようになります。


注意事項

Schedulable Apexを本番環境で運用する際には、いくつかの重要な制約と考慮事項があります。

1. ガバナ制限 (Governor Limits)

Schedulable Apexの`execute`メソッドは、他のApexトランザクションと同様にガバナ制限の対象となります。1回の実行で発行できるSOQLクエリの数(100件)、DMLステートメントの数(150件)、合計CPU時間(10,000ミリ秒)などが制限されています。大量のレコードを処理しようとすると、これらの制限に容易に抵触します。そのため、Schedulable Apexは処理の「起動トリガー」として使い、実際の重い処理はBatch Apexに委譲するのが鉄則です。

2. APIとジョブ数の制限

một tổ chức Salesforce có thể có tối đa 100 công việc Apex được lên lịch cùng một lúc. また、`System.schedule` メソッドを24時間以内に呼び出せる回数にも制限があります(組織のエディションによりますが、通常は100回またはスケジュール済みジョブの最大数の大きい方)。多数の異なるスケジュールジョブが必要な場合、この制限が問題になることがあります。この問題を回避するため、後述する「スケジューラーフレームワーク」という設計パターンが用いられることがあります。

3. 実行コンテキストと権限 (Permissions)

スケジュールされたジョブは、そのジョブをスケジュールしたユーザーの権限で実行されます。つまり、そのユーザーがアクセスできないオブジェクトや項目には、ジョブもアクセスできません。このため、十分な権限を持つインテグレーションユーザーやシステム管理者としてジョブをスケジュールすることが一般的です。また、クラスに `with sharing` または `without sharing` キーワードを明示的に指定し、レコードの可視性を制御することが重要です。

4. エラー処理 (Error Handling)

バッチジョブはバックグラウンドで実行されるため、エラーが発生してもユーザーには即座に通知されません。`execute` メソッド全体を `try-catch` ブロックで囲み、例外が発生した場合には、エラー内容をカスタムオブジェクトに記録したり、`Messaging.SingleEmailMessage` を使ってシステム管理者にメールで通知したりする堅牢なエラー処理メカニズムを実装することが不可欠です。エラーを放置すると、データ不整合やビジネスプロセスの停止に繋がる可能性があります。

5. テストクラスの実装

Schedulable Apexも、本番環境にデプロイする前にApexテストクラスでカバレッジを75%以上にする必要があります。テストクラス内では、`Test.startTest()` と `Test.stopTest()` メソッドを使用します。`System.schedule` を `startTest` と `stopTest` の間に記述すると、`stopTest` が呼び出された時点でスケジュールされたジョブが同期的に実行されるため、ジョブの実行結果をアサーション(`System.assertEquals`など)で検証できます。


まとめとベストプラクティス

Schedulable Apexは、Salesforceの自動化能力を大幅に拡張する強力な機能です。定期的なデータメンテナンス、レポート作成、システム連携など、多様な用途で活用できます。しかし、その強力さゆえに、ガバナ制限や設計パターンを理解せずに使用すると、パフォーマンス問題や運用上の課題を引き起こす可能性があります。

以下に、Schedulable Apexを効果的に活用するためのベストプラクティスをまとめます。

1. Schedulable Apexは「起動役」に徹する

最も重要なベストプラクティスです。`execute` メソッド内には最小限のロジックのみを記述し、実際のデータ処理は Batch ApexQueueable Apex に委譲してください。これにより、ガバナ制限を回避し、より大量のデータを安定して処理できます。Schedulable Apexは、あくまでバッチジョブを開始するための「目覚まし時計」として機能させるのが理想です。

2. 設定のハードコーディングを避ける

CRON式、クエリの条件、通知先のメールアドレスなどをコード内に直接書き込む(ハードコーディングする)のは避けるべきです。これらの設定は、カスタムメタデータ型 (Custom Metadata Types)カスタム設定 (Custom Settings) に保存しましょう。これにより、管理者はコードを修正・デプロイすることなく、本番環境でジョブのスケジュールや動作を柔軟に変更できます。

3. スケジューラーフレームワークの導入を検討する

「スケジュール済みジョブは100件まで」という制限は、多くのプロジェクトで課題となります。この問題を解決するため、一つのマスターとなるSchedulable Apexを非常に短い間隔(例:15分ごと)で実行させる設計パターンがあります。このマスタースケジューラーは、実行されるたびにカスタムオブジェクトやカスタムメタデータを参照し、「今、実行すべき論理的なジョブは何か?」を判断します。そして、条件に合致するジョブをBatch ApexやQueueable Apexとして起動します。これにより、実質的に100件を超えるジョブを管理することが可能になります。

4. 冪等性(Idempotency)を意識する

冪等性(べきとうせい)とは、ある操作を1回行っても、複数回行っても、結果が同じであるという性質です。ネットワークの問題などでジョブが再実行されてしまう可能性もゼロではありません。例えば、「月次レポートを作成する」ジョブが2回実行されても、同じレポートが2つ作成されないように設計することが重要です。処理の最初に「今月のレポートは既に存在するか?」をチェックするなどの工夫で、冪等性を担保できます。

これらの原則とベストプラクティスに従うことで、あなたはSalesforceプラットフォーム上で、スケーラブルで信頼性の高い、メンテナンス性に優れた自動化処理を構築することができるでしょう。

コメント