Apex の一括処理の使用
Apex の一括処理を使用するには、Salesforce が提供するインターフェース Database.Batchable を実装する Apex クラスを記述し、次にプログラムでクラスを呼び出します。
Apex の一括処理ジョブの実行を監視または停止するには、[設定] から、[クイック検索] ボックスに「Apex ジョブ」と入力し、[Apex ジョブ] を選択します。
Database.Batchable インターフェースの実装
-
start メソッド:
1global (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContext bc) {}インターフェースメソッド execute に渡すレコードまたはオブジェクトを収集するには、Apex 一括処理ジョブの冒頭で start メソッドをコールします。このメソッドは、Database.QueryLocator オブジェクト、またはジョブに渡すレコードやオブジェクトが含まれる Iterable オブジェクトを返します。
単純なクエリ (SELECT) を使用して一括処理ジョブのオブジェクトの範囲を生成する場合は、Database.QueryLocator オブジェクトを使用します。QueryLocator オブジェクトを使用する場合、SOQL クエリによって取得されるレコード合計数に対するガバナ制限は無視されます。たとえば、Account オブジェクトに対する Apex の一括処理ジョブでは、組織内のすべての取引先レコード (最大 5000 万件のレコード) の QueryLocator を返すことができます。また、Contact オブジェクトに対して共有再適用を行うと、組織内のすべての取引先レコードの QueryLocator が返されます。
Iterable オブジェクトは、一括処理ジョブに複雑な範囲を作成する場合に使用します。また、リスト全体を反復する独自のカスタムプロセスを作成するために Iterable オブジェクトを使用することもできます。 -
execute メソッド
1global void execute(Database.BatchableContext BC, list<P>){}データの処理単位ごとに必要な処理を実行するには、execute メソッドを使用します。このメソッドは、メソッドに渡すレコードのバッチごとにコールされます。
このメソッドは次を取得します。- Database.BatchableContext オブジェクトへの参照。
- List<sObject> などの sObjects のリストまたはパラメータ化された型のリスト。Database.QueryLocator を使用している場合は、返されたリストを使用します。
レコードの一括処理は、start メソッドから受け取る順序で実行される傾向にあります。ただし、レコードの一括処理が実行される順序はさまざまな要素に応じて変わります。実行の順序は保証されません。
-
finish メソッド
1global void finish(Database.BatchableContext BC){}確認メールの送信や後処理操作を行う場合に、finish メソッドを使用します。このメソッドは、すべてのバッチが処理された後にコールされます。
Apex の一括処理ジョブの各実行は、個別のトランザクションとみなされます。たとえば、1,000 件のレコードを含む Apex の一括処理ジョブが、Database.executeBatch から任意の scope パラメータを指定せずに実行されると、このジョブはそれぞれ 200 件のレコードを含む 5 つのトランザクションとみなされます。Apex のガバナ制限は、各トランザクションでリセットされます。最初のトランザクションが成功し、2 番���が失敗した場合、最初のトランザクションで行われたデータベースの更新はロールバックされません。
Database.BatchableContext の使用
Database.Batchable インターフェースのすべてのメソッドは Database.BatchableContext オブジェクトへの参照を必要とします。このオブジェクトは、一括処理ジョブの進行状況を追跡するために使用します。
| 名前 | 引数 | 戻り値 | 説明 |
|---|---|---|---|
| getJobID | ID | この一括処理ジョブに関連付けられている AsyncApexJob オブジェクトの ID を文字列として返します。このメソッドは、一括処理ジョブのレコードの進行状況を追跡するために使用します。System.abortJob メソッドでもこの ID を使用できます。 |
次の例では、Database.BatchableContext を使用して、一括処理ジョブに関連付けられている AsyncApexJob をクエリします。
1global void finish(Database.BatchableContext BC){
2 // Get the ID of the AsyncApexJob representing this batch job
3 // from Database.BatchableContext.
4 // Query the AsyncApexJob object to retrieve the current job's information.
5 AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed,
6 TotalJobItems, CreatedBy.Email
7 FROM AsyncApexJob WHERE Id =
8 :BC.getJobId()];
9 // Send an email to the Apex job's submitter notifying of job completion.
10 Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
11 String[] toAddresses = new String[] {a.CreatedBy.Email};
12 mail.setToAddresses(toAddresses);
13 mail.setSubject('Apex Sharing Recalculation ' + a.Status);
14 mail.setPlainTextBody
15 ('The batch Apex job processed ' + a.TotalJobItems +
16 ' batches with '+ a.NumberOfErrors + ' failures.');
17 Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
18}Database.QueryLocator を使用した範囲の定義
start メソッドは、一括処理ジョブで使用するレコードを含む Database.QueryLocator オブジェクトまたは Iterable オブジェクトを返します。
1global class SearchAndReplace implements Database.Batchable<sObject>{
2
3 global final String Query;
4 global final String Entity;
5 global final String Field;
6 global final String Value;
7
8 global SearchAndReplace(String q, String e, String f, String v){
9
10 Query=q; Entity=e; Field=f;Value=v;
11 }
12
13 global Database.QueryLocator start(Database.BatchableContext BC){
14 return Database.getQueryLocator(query);
15 }
16
17 global void execute(Database.BatchableContext BC, List<sObject> scope){
18 for(sobject s : scope){
19 s.put(Field,Value);
20 }
21 update scope;
22 }
23
24 global void finish(Database.BatchableContext BC){
25 }
26}Apex の一括処理に Iterable オブジェクトを使用した範囲の定義
start メソッドは、一括処理ジョブで使用するレコードを含む Database.QueryLocator オブジェクトまたは Iterable オブジェクトを返します。Iterable オブジェクトを使用すると、より簡単に項目を返すことができます。
1global class batchClass implements Database.batchable{
2 global Iterable start(Database.BatchableContext info){
3 return new CustomAccountIterable();
4 }
5 global void execute(Database.BatchableContext info, List<Account> scope){
6 List<Account> accsToUpdate = new List<Account>();
7 for(Account a : scope){
8 a.Name = 'true';
9 a.NumberOfEmployees = 70;
10 accsToUpdate.add(a);
11 }
12 update accsToUpdate;
13 }
14 global void finish(Database.BatchableContext info){
15 }
16}Database.executeBatch メソッドを使用した一括処理ジョブの送信
- Database.Batchable インターフェースを実装するクラスのインスタンス。
- 省略可能なパラメータ scope。このパラメータは、execute メソッドに渡すレコードの数を指定します。このパラメータは、メソッドに渡す各レコードに対して多数の処理があり、ガバナ制限に達する場合に使用します。レコード数を制限することによって、トランザクションあたりの処理が制限されます。この値は 0 より大きくする必要があります。一括処理クラスの start メソッドが QueryLocator を返す場合、Database.executeBatch の省略可能な範囲パラメータには最大値 2,000 を指定できます。これより大きい値に設定すると、Salesforce では、QueryLocator が返すレコードを、最大 2,000 レコードまでの、より小さいバッチに分割します。一括処理クラスの start メソッドが Iterable を返す場合、scope パラメータの値に上限はありません。ただし、大きな数値を使用すると他の制限が適用される場合があります。
1ID batchprocessid = Database.executeBatch(reassign);
2
3AsyncApexJob aaj = [SELECT Id, Status, JobItemsProcessed, TotalJobItems, NumberOfErrors
4 FROM AsyncApexJob WHERE ID =: batchprocessid ];System.abortJob メソッドでもこの ID を使用できます。
詳細は、『Salesforce および Force.com のオブジェクトリファレンス』の「AsyncApexJob」を参照してください。
Apex Flex キュー内での一括処理ジョブの保留
Apex Flex キューでは、100 件まで一括処理ジョブを送信できます。
- 一括処理ジョブは Apex Flex キューに置かれ、その状況は Holding に設定されます。
- Apex Flex キューが最大ジョブ数の 100 に達した場合、Database.executeBatch は LimitException を発生させて、ジョブをキューに追加しません。
Apex Flex キュー内のジョブの並び替え
送信したジョブの状況が Holding である間は、Salesforce ユーザインターフェースでジョブを並び替えてどの一括処理ジョブが最初に処理されるかを制御できます。これを行うには、[設定] から、[クイック検索] ボックスに「Apex Flex キュー」と入力し、[Apex Flex キュー] を選択します。
または、Apex メソッドを使用して、Flex キュー内の一括処理ジョブを並び替えることができます。新しい位置にジョブを移動するには、いずれかの System.FlexQueue メソッドをコールします。メソッドにジョブ ID と、移動するジョブの新しい位置の次にあるジョブの ID (該当する場合) を渡します。以下に例を示します。
1Boolean isSuccess = System.FlexQueue.moveBeforeJob(jobToMoveId, jobInQueueId);システムリソースが使用可能になったら、システムが Apex Flex キューの先頭から次のジョブを取り出し、一括処理ジョブキューに移動します。組織ごとに、システムでは最大 5 件のキュー内のジョブまたは有効なジョブを同時に処理できます。移動したこれらのジョブの状況は、Holding から Queued に変わります。キュー内にあるジョブは、システムが新しいジョブを処理できる状態になると実行されます。[Apex ジョブ] ページで、キューに入れたジョブを監視できます。
一括処理ジョブの状況
次の表に、一括処理ジョブで発生するすべての状況と、それぞれの説明を示します。
| 状況 | 説明 |
|---|---|
| 保留 | ジョブは送信済みで、システムリソースが使用可能になって処理用のキューにジョブを追加できるようになるまで Apex Flex キュー内に保持されています。 |
| キュー | ジョブは実行待ちです。 |
| 準備中 | ジョブの start メソッドが呼び出されました。この状況は、レコードのバッチサイズに応じて数分かかることがあります。 |
| 処理中 | ジョブは処理中です。 |
| 中止 | ジョブはユーザによって中止されました。 |
| 完了 | ジョブはエラーあり/なしで完了しました。 |
| 失敗 | ジョブでシステム障害が発生しました。 |
System.scheduleBatch メソッドの使用
System.scheduleBatch メソッドを使用して、一括処理ジョブを将来のある時点で一度実行するようにスケジュールできます。
- Database.Batchable インターフェースを実装するクラスのインスタンス。
- ジョブ名。
- ジョブが実行を開始するまでの分単位の期間。
- 範囲の値 (省略可能)。このパラメータは、execute メソッドに渡すレコードの数を指定します。このパラメータは、メソッドに渡す各レコードに対して多数の処理があり、ガバナ制限に達する場合に使用します。レコード数を制限することによって、トランザクションあたりの処理が制限されます。この値は 0 より大きくする必要があります。start メソッドが QueryLocator を返す場合、System.scheduleBatch の省略可能な範囲パラメータには最大値 2,000 を指定できます。これより大きい値に設定すると、Salesforce では、QueryLocator が返すレコードを、最大 2,000 レコードまでの、より小さいバッチに分割します。start メソッドが Iterable を返す場合、scope パラメータの値に上限はありません。ただし、大きな数値を使用すると他の制限が適用される場合があります。
System.scheduleBatch メソッドは、スケジュール済みジョブ ID (CronTrigger ID) を返します。
1String cronID = System.scheduleBatch(reassign, 'job example', 1);
2
3CronTrigger ct = [SELECT Id, TimesTriggered, NextFireTime
4 FROM CronTrigger WHERE Id = :cronID];
5
6// TimesTriggered should be 0 because the job hasn't started yet.
7System.assertEquals(0, ct.TimesTriggered);
8System.debug('Next fire time: ' + ct.NextFireTime);
9// For example:
10// Next fire time: 2013-06-03 13:31:23詳細は、『Salesforce および Force.com のオブジェクトリファレンス』の「CronTrigger」を参照してください。
Apex の一括処理の例
1global class UpdateAccountFields implements Database.Batchable<sObject>{
2 global final String Query;
3 global final String Entity;
4 global final String Field;
5 global final String Value;
6
7 global UpdateAccountFields(String q, String e, String f, String v){
8 Query=q; Entity=e; Field=f;Value=v;
9 }
10
11 global Database.QueryLocator start(Database.BatchableContext BC){
12 return Database.getQueryLocator(query);
13 }
14
15 global void execute(Database.BatchableContext BC,
16 List<sObject> scope){
17 for(Sobject s : scope){s.put(Field,Value);
18 } update scope;
19 }
20
21 global void finish(Database.BatchableContext BC){
22
23 }
24
25}1// Query for 10 accounts
2String q = 'SELECT Industry FROM Account LIMIT 10';
3String e = 'Account';
4String f = 'Industry';
5String v = 'Consulting';
6Id batchInstanceId = Database.executeBatch(new UpdateAccountFields(q,e,f,v), 5);1// Query for accounts that aren't in the Recycle Bin
2String q = 'SELECT Industry FROM Account WHERE isDeleted=false LIMIT 10';
3String e = 'Account';
4String f = 'Industry';
5String v = 'Consulting';
6Id batchInstanceId = Database.executeBatch(new UpdateAccountFields(q,e,f,v), 5);1// Query for invoices that aren't in the Recycle Bin
2String q =
3 'SELECT Description__c FROM Invoice_Statement__c WHERE isDeleted=false LIMIT 10';
4String e = 'Invoice_Statement__c';
5String f = 'Description__c';
6String v = 'Updated description';
7Id batchInstanceId = Database.executeBatch(new UpdateInvoiceFields(q,e,f,v), 5);1global class OwnerReassignment implements Database.Batchable<sObject>{
2String query;
3String email;
4Id toUserId;
5Id fromUserId;
6
7global Database.querylocator start(Database.BatchableContext BC){
8 return Database.getQueryLocator(query);}
9
10global void execute(Database.BatchableContext BC, List<sObject> scope){
11 List<Account> accns = new List<Account>();
12
13 for(sObject s : scope){Account a = (Account)s;
14 if(a.OwnerId==fromUserId){
15 a.OwnerId=toUserId;
16 accns.add(a);
17 }
18 }
19
20update accns;
21
22}
23global void finish(Database.BatchableContext BC){
24Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
25
26mail.setToAddresses(new String[] {email});
27mail.setReplyTo('batch@acme.com');
28mail.setSenderDisplayName('Batch Processing');
29mail.setSubject('Batch Process Completed');
30mail.setPlainTextBody('Batch Process has completed');
31
32Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
33}
34}1OwnerReassignment reassign = new OwnerReassignment();
2reassign.query = 'SELECT Id, Name, Ownerid FROM Account ' +
3 'WHERE ownerid=\'' + u.id + '\'';
4reassign.email='admin@acme.com';
5reassign.fromUserId = u;
6reassign.toUserId = u2;
7ID batchprocessid = Database.executeBatch(reassign);1global class BatchDelete implements Database.Batchable<sObject> {
2 public String query;
3
4 global Database.QueryLocator start(Database.BatchableContext BC){
5 return Database.getQueryLocator(query);
6 }
7
8 global void execute(Database.BatchableContext BC, List<sObject> scope){
9 delete scope;
10 DataBase.emptyRecycleBin(scope);
11 }
12
13 global void finish(Database.BatchableContext BC){
14 }
15}1BatchDelete BDel = new BatchDelete();
2Datetime d = Datetime.now();
3d = d.addDays(-1);
4// Replace this value with the folder ID that contains
5// the documents to delete.
6String folderId = '00lD000000116lD';
7// Query for selecting the documents to delete
8BDel.query = 'SELECT Id FROM Document WHERE FolderId=\'' + folderId +
9 '\' AND CreatedDate < '+d.format('yyyy-MM-dd')+'T'+
10 d.format('HH:mm')+':00.000Z';
11// Invoke the batch job.
12ID batchprocessid = Database.executeBatch(BDel);
13System.debug('Returned batch process ID: ' + batchProcessId);Apex の一括処理でのコールアウトの使用
1global class SearchAndReplace implements Database.Batchable<sObject>,
2 Database.AllowsCallouts{
3}コールアウトには、HTTP 要求および webService キーワードで定義されたメソッドが含まれています。
Apex の一括処理での状態の使用
Apex の一括処理ジョブの各実行は、個別のトランザクションとみなされます。たとえば、1,000 件のレコードを含む Apex の一括処理ジョブが、任意の scope パラメータを指定せずに実行されると、このジョブはそれぞれ 200 件のレコードを含む 5 つのトランザクションとみなされます。
クラス定義で Database.Stateful を指定すると、これらのトランザクション間で状態を保持できます。Database.Stateful を使用するとき、インスタンスメンバー変数のみがトランザクション間で値を保持します。静的メンバー変数は、トランザクション間で値を保持せず、リセットされます。状態を保持すると、処理されているレコードをカウントまたは集計する場合に役立ちます。たとえば、ジョブで商談レコードが処理されたとします。execute でメソッドを定義し、処理された商談数の合計を集計できます。
Database.Stateful を指定しない場合、すべての静的メンバー変数とインスタンスメンバー変数が元の値に戻されます。
1global class SummarizeAccountTotal implements
2 Database.Batchable<sObject>, Database.Stateful{
3
4 global final String Query;
5 global integer Summary;
6
7 global SummarizeAccountTotal(String q){Query=q;
8 Summary = 0;
9 }
10
11 global Database.QueryLocator start(Database.BatchableContext BC){
12 return Database.getQueryLocator(query);
13 }
14
15 global void execute(
16 Database.BatchableContext BC,
17 List<sObject> scope){
18 for(sObject s : scope){
19 Summary = Integer.valueOf(s.get('total__c'))+Summary;
20 }
21 }
22
23global void finish(Database.BatchableContext BC){
24 }
25}1// Implement the interface using a list of Account sObjects
2// Note that the initialState variable is declared as final
3
4global class MyBatchable implements Database.Batchable<sObject> {
5 private final String initialState;
6 String query;
7
8 global MyBatchable(String intialState) {
9 this.initialState = initialState;
10 }
11
12 global Database.QueryLocator start(Database.BatchableContext BC) {
13 // Access initialState here
14
15 return Database.getQueryLocator(query);
16 }
17
18 global void execute(Database.BatchableContext BC,
19 List<sObject> batch) {
20 // Access initialState here
21
22 }
23
24 global void finish(Database.BatchableContext BC) {
25 // Access initialState here
26
27 }
28}initialState はクラスの「最初の」状態でしかありません。これを使用して、一括処理ジョブの実行時にクラスのインスタンス間で情報を受け渡すことはできません。たとえば、execute で initialState の値を変更した場合、2 番目に処理されるレコード群は、新しい値にアクセスできません。アクセスできるのは最初の値のみです。
Apex の一括処理のテスト
Apex の一括処理をテストするとき、execute メソッドの 1 つの実行だけをテストできます。executeBatch メソッドの scope パラメータを使用して、execute メソッドに渡されるレコード数を制限し、ガバナ制限に達しないようにします。
executeBatch メソッドは、匿名プロセスを開始します。Apex の一括処理をテストするときには、結果に対してテストする前に非同期で処理された一括処理ジョブが完了していることを確認してください。テストメソッド startTest と stopTest を executeBatch メソッドの前後に使用して、非同期で処理された一括処理ジョブが完了してからテストを続行するようにします。startTest メソッドの後に実行されたすべての非同期コールはシステムによって収集されます。stopTest を実行する場合、すべての非同期プロセスが同期して実行されます。startTest メソッドおよび stopTest メソッド内に executeBatch メソッドを含めない場合、一括処理ジョブはテストメソッドの最後に実行されます。この実行順序は、API バージョン 25.0 以降を使用して保存された Apex には適用されますが、それより前のバージョンには適用されません。
1public static testMethod void testBatch() {
2 user u = [SELECT ID, UserName FROM User
3 WHERE username='testuser1@acme.com'];
4 user u2 = [SELECT ID, UserName FROM User
5 WHERE username='testuser2@acme.com'];
6 String u2id = u2.id;
7// Create 200 test accounts - this simulates one execute.
8// Important - the Salesforce.com test framework only allows you to
9// test one execute.
10
11 List <Account> accns = new List<Account>();
12 for(integer i = 0; i<200; i++){
13 Account a = new Account(Name='testAccount'+'i',
14 Ownerid = u.ID);
15 accns.add(a);
16 }
17
18 insert accns;
19
20 Test.StartTest();
21 OwnerReassignment reassign = new OwnerReassignment();
22 reassign.query='SELECT ID, Name, Ownerid ' +
23 'FROM Account ' +
24 'WHERE OwnerId=\'' + u.Id + '\'' +
25 ' LIMIT 200';
26 reassign.email='admin@acme.com';
27 reassign.fromUserId = u.Id;
28 reassign.toUserId = u2.Id;
29 ID batchprocessid = Database.executeBatch(reassign);
30 Test.StopTest();
31
32 System.AssertEquals(
33 database.countquery('SELECT COUNT()'
34 +' FROM Account WHERE OwnerId=\'' + u2.Id + '\''),
35 200);
36
37 }
38}System.Test.enqueueBatchJobs および System.Test.getFlexQueueOrder メソッドを使用して、テストのコンテキスト内でノーオペレーションジョブをキューに追加し、並び替えます。
Apex の一括処理のガバナ制限
- 最大 5 件の一括処理ジョブを同時にキューに追加するか、有効にできます。
- 最大 100 個の Holding 一括処理ジョブを Apex Flex キュー内で保留できます。
- 実行中のテストでは、最大 5 件の一括処理ジョブを送信できます。
- 24 時間での Apex 一括処理メソッドの最大実行数は、250,000 または組織のユーザライセンス数の 200 倍のいずれか大きい方です。メソッドの実行数には、start、execute、および finish メソッドの実行が含まれます。これは組織全体の制限で、他のすべての非同期 Apex (Apex 一括処理、キュー可能 Apex、スケジュール済み Apex、および future メソッド) と共有されます。この制限のカウント対象となるライセンスは、Salesforce フルユーザライセンスまたは Force.com アプリケーションサブスクリプションのユーザライセンスです。Chatter Free、Chatter カスタマーユーザ、カスタマーポータルユーザ、およびパートナーポータルユーザライセンスは含まれません。
- Apex 一括処理の start メソッドは、ユーザごとに同時に最大 15 個のクエリカーソルを開くことができます。Apex 一括処理の execute および finish メソッドにはそれぞれ、ユーザごとに開けるクエリカーソルは 5 個までという制限があります。
- Database.QueryLocator オブジェクトでは最大 5,000 万件のレコードが返されます。5,000 万件以上のレコードが返された場合、一括処理ジョブは即座に終了し「失敗」とマークされます。
- 一括処理クラスの start メソッドが QueryLocator を返す場合、Database.executeBatch の省略可能な範囲パラメータには最大値 2,000 を指定できます。これより大きい値に設定すると、Salesforce では、QueryLocator が返すレコードを、最大 2,000 レコードまでの、より小さいバッチに分割します。一括処理クラスの start メソッドが Iterable を返す場合、scope パラメータの値に上限はありません。ただし、大きな数値を使用すると他の制限が適用される場合があります。
- Database.executeBatch の scope パラメータ (省略可能) でサイズが指定されない場合、Salesforce では start メソッドによって返されるレコードを 200 個ずつのバッチに分割します。次に、各バッチを execute メソッドに渡します。Apex ガバナ制限は、execute の各実行でリセットされます。
- start、execute、および finish メソッドは、それぞれ最大 10 回のコールアウトを実装できます。
- Apex の一括処理ジョブの start メソッドは、組織内で一度に 1 つのみ実行できます。キュー内のまだ開始されていない一括処理ジョブは、開始されるまで保持されます。なお、この制限により一括処理ジョブが失敗することはありません。また、複数のジョブが実行されている場合は、Apex の一括処理ジョブの execute メソッドが並行して実行されます。
Apex の一括処理のベストプラクティス
- 一括処理ジョブをトリガから開始する場合は、細心の注意を払ってください。トリガで一括処理ジョブが制限を超えて追加されないようにする必要があります。特に、API の一括更新、インポートウィザード、ユーザインターフェースを使用したレコードの一括変更、および複数のレコードを一度に更新するすべての処理については十分に考慮してください。
- Database.executeBatch をコールしたときに Salesforce ��行うのは、そのジョブをキューに入れることのみです。実際の実行は、サービスの使用可能状態に応じて遅れる場合があります。
- Apex の一括処理をテストするとき、execute メソッドの 1 つの実行だけをテストできます。executeBatch メソッドの scope パラメータを使用して、execute メソッドに渡されるレコード数を制限し、ガバナ制限に達しないようにします。
- executeBatch メソッドは、匿名プロセスを開始します。Apex の一括処理をテストするときには、結果に対してテストする前に非同期で処理された一括処理ジョブが完了していることを確認してください。テストメソッド startTest と stopTest を executeBatch メソッドの前後に使用して、非同期で処理された一括処理ジョブが完了してからテストを続行するようにします。
- ジョブトランザクション全体でインスタンスメンバー変数またはデータを共有する場合は、クラス定義で Database.Stateful を使用します。これを使用しない場合、各トランザクションの開始時にすべてのメンバー変数が初期状態にリセットされます。
- future として宣言されたメソッドは、Database.Batchable インターフェースを実装するクラスでは使用できません。
- future として宣言されたメソッドは、Apex の一括処理クラスからはコールできません。
- Apex の一括処理ジョブが実行されると、一括処理ジョブを送信したユーザにメール通知が送信されます。管理パッケージにコードが含まれ、登録組織が一括処理ジョブを実行している場合、[Apex 例外通知受信者] 項目にリストされた受信者に通知が送信されます。
- 各メソッドの実行では、標準のガバナ制限が、匿名ブロック、Visualforce コントローラ、または WSDL メソッド同様に適用されます。
- Apex の一括処理が呼び出されるたびに AsyncApexJob レコードが作成されます。ジョブの状況、エラーの数、進行状況、送信者を取得する SOQL クエリを構成するには、AsyncApexJob レコードの ID を使用します。AsyncApexJob オブジェクトについての詳細は、『Salesforce および Force.com のオブジェクトリファレンス』の「AsyncApexJob」を参照してください。
- 10,000 件ごとの AsyncApexJob レコードに対して、Apex では、内部で使用するための BatchApexWorker タイプの AsyncApexJob レコードを作成します。すべての AsyncApexJob レコードをクエリする場合は、JobType 項目を使用して BatchApexWorker タイプのレコードを除外することをお勧めします。除外しない場合、クエリにより 10,000 件の AsyncApexJob レコードごとに複数のレコードが返されます。AsyncApexJob オブジェクトについての詳細は、『Salesforce および Force.com のオブジェクトリファレンス』の「AsyncApexJob」を参照してください。
- クラス内のすべてのメソッドは global または public として定義する必要があります。
- 共有再適用の場合、一括処理内のレコードに対する Apex による共有管理を、すべて execute メソッドで削除してから再作成することをお勧めします。このプロセスにより、共有が正確で完全になります。
- Salesforce サービスメンテナンスダウンタイム前にキューに入れられた一括処理ジョブは、キューに入れられたままになります。サービスのダウンタイムが終了してシステムリソースが使用可能になったときに、キューにある一括処理ジョブが実行されます。ダウンタイム発生時に一括処理ジョブが実行されていた場合、その一括処理の実行はロールバックされ、サービスが再開された後に再度開始されます。
- 可能ならば、一括処理の数は最小限に抑えてください。Salesforce では、キューベースのフレームワークを使用して、future メソッドや Apex の一括処理などのソースからの非同期プロセスを処理します。このキューは、組織間で要求ワークロードを調整するために使用します。キュー内で 1 つの組織の未処理要求が 2,000 を上回ると、その組織からの以降の要求は遅延し、その間に他の組織からの要求が処理されます。
- 一括処理ジョブができるだけ高速に実行されるようにします。一括処理ジョブを高速に実行するには、Web サービスコールアウト回数を最小限にし、Apex の一括処理コードで使用されるクエリを調整します。キュー内のジョブ数が多い場合、一括処理ジョブの実行時間が長くなるほど、キューにある他のジョブが遅延する可能性が高くなります。
一括処理ジョブのチェーニング
API バージョン 26.0 以降、既存の一括処理ジョブから別の一括処理ジョブを開始するように、ジョブをチェーニングできます。一括処理ジョブをチェーニングすることで、大量のデータを処理する場合など、ジョブでバッチでの処理が必要な場合に、別のジョブが終了するとジョブが開始します。または、一括処理が必要ではない場合は、Queueable Apex の使用を検討してください。
一括処理ジョブをチェーニングするには、現在の一括処理クラスの finish メソッドから Database.executeBatch または System.scheduleBatch をコールします。新しい一括処理ジョブは、現在の一括処理ジョブが終了すると開始します。
以前の API バージョンでは、Apex の一括処理メソッドから Database.executeBatch と System.scheduleBatch はコールできませんでした。使用されるバージョンは、他の一括処理ジョブを開始またはスケジュールする、実行中の一括処理クラスのバージョンです。実行中の一括処理クラスの finish メソッドで、一括処理ジョブを開始するヘルパークラスのメソッドをコールする場合は、ヘルパークラスの API バージョンは関係ありません。