[Salesforce]バッチスケジュールの一通りの書き方

複数クラスにわたってたりしてややこしかったのでメモ。

バッチ

まずはバッチファイル。
ここで実際に動作させたい内容を書く。
枠はこんな感じ。

Batch_sample.apex

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
global with sharing class Batch_sample implements Database.Batchable<sObject>
{
  private String query;
  
  //コンストラクタ
  global Batch_sample(String q){
      query = q;
  }
  
  //データ取得
  global Database.QueryLocator start(Database.BatchableContext BC){
      return Database.getQueryLocator(query);
  }
  
  //開始
  global void execute(Database.BatchableContext BC, List<sObject> scope){
  
      //バッチの処理を記述
      
  }
  
  //完了
  global void finish(Database.BatchableContext BC)
  {
      //完了後の処理があれば
  }
}

バッチを起動させるには以下のようにSOQL文と件数を渡して実行する。

1
2
3
String soql = 'SELECT ID FROM sObject';
Batch_sample b = new Batch_sample(soql);
Database.executeBatch(b, 200);

実行時に指定したSOQLで取得するレコード分、バッチが動作する。
この際に取得出来る件数が、バッチの場合は500万件。
とはいえ、実際には一度の処理では指定した件数分のみ処理し、ガバナ制限がリセットされて再度実行、を繰り返す。
executeBatchの第二引数が一回の処理で実行する件数。
(デフォルトは200件)

バッチ全体の動作は10分以内、というガバナ制限もあり。
(100万件単位になってくると結構厳しい数字っぽい)

スケジューラー

設定したバッチをスケジューラーとして実行させる。
以下のように、Schedulableクラスをimplementsする。

Schedule_sample.apxc

1
2
3
4
5
6
7
8
9
global class Schedule_sample implements Schedulable {
  private final Integer BATCH_SIZE = 200;
  
  global void execute(SchedulableContext ctx) {
      String soql = 'SELECT ID FROM sObject';
      Batch_sample b = new Batch_sample(soql);
      Database.executeBatch(b, BATCH_SIZE);
  }
}

このクラスをジョブに追加することでバッチをスケジューリング出来る。

スケジュールに追加

追加方法は2つある

設定画面から追加

設定->開発->Apexクラスを選択。
画面内のApexをスケジュールをクリック。

この中で毎月や毎日、などを選択できる。
終了日も設定出来るので、ずっと動作するさせるものに関しては長めに設定しておく。

コードで実行

設定画面から追加での最大のデメリットは実行時間が毎時0分のみ、と、分の指定ができないところ。
これをさせようと思うとコードからジョブに追加してやる必要がある。

以下が追加させるコード

System.schedule('ジョブ名','0 0 * * * ?', new Schedule_sample());

第二引数に指定しているものは、クーロン式、というもので、ここで時間指定をしている。
これは、左から、秒、分、時、日、月、曜日、年となっている。
(年は省略化)

例)

  • ‘0 0 13 * * ?’:毎日13時に実行
  • ‘0 0 10 ? * MON-FRI’:月~金の10時に実行
  • ‘0 0 * * * ?’:毎時0分に実行
  • ‘0 30 * * * ?’:毎時30分に実行

秒のみの指定は怖くて試してません。

この実行式を開発者コンソールの匿名実行から実行することでジョブに追加させられる。

コードを書いて、実行ボタンをクリック。

追加されたジョブは設定画面の、ジョブ->スケジュール済みジョブから確認できる。

動作テスト

実際に開発中にいちいちスケジュールさせてジョブが実行されるのを待つのはあまりにもめんどくさい。
バッチを起動させるコードを匿名実行から起動させてもよいがそれでも待ち時間が長いので、結局バッチ処理特有の部分をコメントアウトして、単なるクラスにしてそれを直接実行させる方法で確認した。

以下のようにコメントアウトした。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//global with sharing class Batch_sample implements Database.Batchable<sObject>
public class Batch_sample
{
  /*
  private String query;   
  //コンストラクタ
  global Batch_UpdatePushlist(String q){
      query = q;
  }
  
  //データ取得
  global Database.QueryLocator start(Database.BatchableContext BC){
      return Database.getQueryLocator(query);
  }
  */
  
  //開始
  public void execute(List<sObject> scope){
  //global void execute(Database.BatchableContext BC, List<sObject> scope){
  
      //バッチの処理を記述
      
  }
  
  //global void finish(Database.BatchableContext BC){}
}

これを匿名実行からSOQLでデータを取得してからそれを渡してやりつつ実行する。

1
2
3
4
String soql = 'SELECT ID FROM sObject';
List<sObject> data = Database.query(soql);
Batch_sample batch = new Batch_sample();
batch.execute(data);

もっとスマートなやり方があったらぜひ。

テスト

テストコードはスケジューラに対して実行する。

Schedule_sample_Test.apxc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@isTest
public class Schedule_sample_Test {
  public static String CRON_EXP = '0 0 0 15 3 ? 2022';
  
  static testmethod void test() {
      //データ準備
  
      Test.startTest();
      String jobId = System.schedule('ScheduleApexClassTest', CRON_EXP, new Batch_sample());
      Test.stopTest();
      
      //バッチ後のデータ確認
  }
}

指定するクーロン式はなんでもよくて、Test.stopTest();の後にすぐにスケジュールが実行される。

参考

スケジュール可能なクラスのテストの追加 | Apex ワークブック | Salesforce Developers
セールスフォースの豆知識: スケジュール実行するApexのテストメソッドと実行時刻の詳細設定
【Salesforce】Apexジョブの書き方 : 怠けろ!プログラマ!

   このエントリーをはてなブックマークに追加