背景と適用シナリオ
Salesforceプラットフォームで働く私たちSalesforce 開発者 (Salesforce Developer)にとって、ビジネスプロセスの自動化は日常的な課題です。多くの自動化は、ユーザがレコードを作成・更新したり、ボタンをクリックしたりといった、リアルタイムのアクションによってトリガーされます。しかし、特定の時間に、あるいは定期的に実行する必要があるビジネス要件も数多く存在します。例えば、「毎晩深夜にデータをクリーンアップする」「週に一度レポートを生成して経営陣にメールで送信する」「毎時外部システムとデータを同期する」といったケースです。
このような時間基準の自動化要件を実現するためにSalesforceが提供している強力なツールが、Schedulable Apex (スケジュールApex) です。これは、開発者がApexクラスを記述し、指定したスケジュールで自動的に実行させることを可能にするフレームワークです。ユーザの操作を介さずにバックグラウンドで処理を実行できるため、データの一括処理、定期的なメンテナンス作業、システム間の連携など、幅広いシナリオで活用されています。
この記事では、Salesforce開発者の視点から、Schedulable Apexの基本的な仕組み、具体的な実装方法、そして本番環境で安定して運用するための注意点やベストプラクティスについて、コード例を交えながら詳しく解説していきます。
原理説明
Schedulable Apexの核心は、Salesforceが提供する `Schedulable` というインタフェース (Interface) にあります。このインタフェースをApexクラスに実装 (implements) することで、そのクラスはSalesforceのスケジューラから呼び出し可能なジョブとして認識されるようになります。
Schedulable インタフェース
`Schedulable` インタフェースには、実装しなければならないメソッドが一つだけ定義されています。
`execute(SchedulableContext sc)`
この `execute` メソッドが、スケジュールされた日時に到達したときにSalesforceプラットフォームによって呼び出される処理の本体です。すべてのビジネスロジックは、このメソッド内に記述します。引数として渡される `SchedulableContext` オブジェクトには、現在実行中のジョブのIDなどのコンテキスト情報が含まれており、`sc.getTriggerId()` を使って取得できます。
ジョブのスケジューリング
Schedulable Apexクラスを作成しただけでは、自動実行はされません。`System.schedule` メソッドを使って、いつ、どのクラスを実行するかをシステムに登録する必要があります。このメソッドは通常、開発者コンソールの匿名実行ウィンドウや、別のApexクラス内から呼び出されます。
`System.schedule` メソッドの基本的なシグネチャは以下の通りです。
`System.schedule(jobName, cronExpression, schedulableClass)`
- jobName: スケジュールジョブの一意の名前(String型)。[設定] > [ジョブ] > [スケジュール済みジョブ] のUIで表示される名前です。
- cronExpression: ジョブを実行するスケジュールを定義するCron式 (Cron Expression)(String型)。
- schedulableClass: `Schedulable` インタフェースを実装したクラスのインスタンス。
Cron式 (Cron Expression)
Cron式は、ジョブの実行タイミングを柔軟に指定するための表記法です。スペースで区切られた6つまたは7つのフィールドで構成されます。
`Seconds Minutes Hours Day_of_month Month Day_of_week [Optional_year]`
例えば、以下のような指定が可能です。
- `0 0 1 * * ?` : 毎日午前1時に実行
- `0 30 8 ? * MON-FRI` : 月曜日から金曜日までの毎朝8時30分に実行
- `0 0 12 1 * ?` : 毎月1日の正午に実行
`?` は「指定なし」を意味し、Day_of_monthとDay_of_weekのどちらか一方には必ず指定する必要があります。このCron式を使いこなすことで、非常に複雑なスケジュール要件にも対応できます。
示例代码
ここでは、Salesforceの公式ドキュメントで紹介されている典型的な例を基に、Schedulable Apexの実装方法を見ていきましょう。この例では、毎週特定の曜日に実行されるシンプルなジョブを作成します。
Schedulable Apex クラスの作成
まず、`Schedulable` インタフェースを実装したクラスを作成します。ここでは、簡単なデバッグメッセージをログに出力するだけのクラスを例とします。実際のプロジェクトでは、`execute` メソッド内にデータ処理ロジック(SOQLクエリやDML操作など)を記述します。
// Schedulable インタフェースを実装したクラスを定義します。 // 'global' 修飾子が必要です。 global class SchedulableExample implements Schedulable { // スケジュールされた時刻になると、この execute メソッドが呼び出されます。 // SchedulableContext オブジェクトには、ジョブIDなどの実行コンテキスト情報が含まれます。 global void execute(SchedulableContext sc) { // ここに実行したいビジネスロジックを記述します。 // 例えば、特定の条件に合致する取引先責任者を検索し、フォローアップのToDoを作成するなど。 List<Account> accounts = [SELECT Id, Name FROM Account WHERE CreatedDate = LAST_N_DAYS:7]; List<Task> tasksToCreate = new List<Task>(); for (Account acc : accounts) { Task t = new Task(); t.Subject = 'Follow up on newly created account'; t.WhatId = acc.Id; tasksToCreate.add(t); } if (!tasksToCreate.isEmpty()) { insert tasksToCreate; } // 実行ログを確認するためにデバッグメッセージを出力します。 System.debug('SchedulableExample executed successfully for ' + accounts.size() + ' accounts.'); } }
ジョブのスケジュール実行
次に、作成したクラスをスケジュールに登録します。開発者コンソールの [Debug] > [Open Execute Anonymous Window] を開き、以下のコードを実行します。
// Schedulableクラスのインスタンスを作成します。 SchedulableExample schExample = new SchedulableExample(); // Cron式を定義します。この例では、毎週金曜日の午後3時に実行されます。 // 形式: 秒 分 時 日 月 曜日 // '0 0 15 ? * FRI' は「毎月、毎週金曜日の15時0分0秒」を意味します。 String cronExpression = '0 0 15 ? * FRI'; // ジョブの名前、Cron式、クラスのインスタンスを渡してスケジュールを登録します。 // 返り値は、スケジュールされたジョブのIDです。 String jobId = System.schedule('Weekly Account Follow-up Job', cronExpression, schExample); // 登録されたジョブのIDをデバッグログに出力して確認します。 System.debug('Scheduled job ID: ' + jobId);
このコードを実行すると、指定したスケジュールで `SchedulableExample` クラスの `execute` メソッドが自動的に呼び出されるようになります。スケジュールされたジョブは、[設定] > [スケジュール済みジョブ] から確認や削除が可能です。
注意事项
Schedulable Apexは便利ですが、本番環境で利用する際にはいくつかの重要な制約や考慮事項があります。
ガバナ制限 (Governor Limits)
Schedulable Apexは非同期処理であるため、同期処理(Visualforceコントローラなど)よりも緩和されたガバナ制限 (Governor Limits) が適用されます。例えば、CPUタイムアウトは60秒(同期処理は10秒)、ヒープサイズは12MB(同期処理は6MB)です。しかし、無制限ではありません。一度の `execute` メソッドの実行で大量のデータを処理しようとすると、依然として制限に達する可能性があります。処理が複雑な場合は、Schedulable ApexからBatch Apex (バッチApex) を呼び出す設計パターンを検討してください。これにより、データを小さなチャンクに分割して処理でき、ガバナ制限を回避しやすくなります。
スケジュール可能なジョブの数
một tổ chức có thể có tối đa 100 công việc Apex được lên lịch đang hoạt động hoặc đang chờ xử lý cùng một lúc. また、`System.schedule` を実行できる回数にも制限があります。設計時には、組織全体でスケジュールするジョブの数を考慮する必要があります。
実行コンテキストと権限
スケジュールされたジョブは、そのジョブをスケジュールしたユーザの権限で実行されます。これは非常に重要なポイントです。もしジョブをスケジュールしたユーザが無効化されると、そのジョブは失敗するようになります。この問題を避けるため、特定のプロファイルを持つ専用のインテグレーションユーザを作成し、そのユーザとしてジョブをスケジュールすることがベストプラクティスとされています。
エラーハンドリング
`execute` メソッド内でハンドルされない例外が発生した場合、ジョブはそこで停止し、再試行は行われません。本番環境で運用するジョブには、堅牢なエラーハンドリングが不可欠です。`try-catch` ブロックを使用して例外を捕捉し、エラー内容をカスタムオブジェクトに記録したり、`Messaging.SingleEmailMessage` クラスを使ってシステム管理者に通知メールを送信したりする仕組みを必ず実装しましょう。
テストクラスの実装
Schedulable Apexのテストは、通常のApexクラスとは少し異なります。テストメソッド内から直接 `System.schedule` を呼び出してジョブを同期的に実行することはできません。代わりに、`Test.startTest()` と `Test.stopTest()` メソッドを使用します。`Test.startTest()` の後で `System.schedule` を呼び出し、`Test.stopTest()` を実行すると、その間にスケジュールされた非同期処理(Schedulable Apexを含む)が同期的に実行されます。
@isTest private class SchedulableExampleTest { @isTest static void testScheduledJob() { // テストデータの準備 List<Account> testAccounts = new List<Account>(); for(Integer i=0; i<5; i++) { testAccounts.add(new Account(Name='Test Account ' + i)); } insert testAccounts; // Test.startTest() と Test.stopTest() の間でスケジュール処理を呼び出す Test.startTest(); // スケジュールジョブを登録 String cronExpression = '0 0 15 ? * FRI'; System.schedule('Test Weekly Job', cronExpression, new SchedulableExample()); Test.stopTest(); // Test.stopTest() の後、スケジュールされたジョブが実行される。 // 結果を検証するアサーションを記述する。 List<Task> createdTasks = [SELECT Id FROM Task]; System.assertEquals(5, createdTasks.size(), '5件のタスクが作成されているべきです。'); } }
まとめとベストプラクティス
Schedulable Apexは、Salesforceプラットフォーム上で時間基準の自動化を実現するための強力かつ不可欠な機能です。定期的なデータメンテナンス、レポート生成、外部システム連携など、その用途は多岐にわたります。
開発者としてSchedulable Apexを効果的に活用するためには、以下のベストプラクティスを心掛けることが重要です。
- コードのバルク化 (Bulkification): `execute` メソッド内のロジックは、常に複数のレコードを効率的に処理できるように設計してください。SOQLクエリやDML操作をループ内で実行することは絶対に避けましょう。
- 設定の外部化 (Externalize Configuration): Cron式や処理対象の条件(例: `WHERE句`)などをコード内にハードコーディングするのではなく、カスタムメタデータ型 (Custom Metadata Types) やカスタム設定 (Custom Settings) に格納しましょう。これにより、コードの変更なしで管理者がジョブの挙動を調整できるようになります。
- 冪等性の確保 (Idempotency): ジョブが何らかの理由で複数回実行されても、システムに悪影響(重複レコードの作成など)を与えないように設計することが理想的です。処理の開始時に、既に処理済みかどうかをチェックするフラグなどを活用します。
- 堅牢なエラーハンドリングと監視: 例外を捕捉し、詳細なエラーログを残し、重要なジョブが失敗した際には即座に管理者に通知する仕組みを構築してください。[設定] > [Apexジョブ] ページを定期的に監視することも重要です。
- 適切なツールの選択: 大量のデータを扱う場合は、Schedulable ApexからBatch Apexを呼び出すことを検討してください。これにより、ガバナ制限を回避し、よりスケーラブルなソリューションを構築できます。
これらの原則に従うことで、信頼性が高く、保守しやすいスケジュールジョブを開発することができます。Schedulable Apexを正しく理解し、活用することで、Salesforceの自動化の可能性をさらに広げることができるでしょう。
コメント
コメントを投稿