Part 9: バッチ処理 (Batch Apex) におけるエラーハンドリング
前回は Apex トリガーのエラーハンドリング を解説しました。
今回は バッチ処理 (Batch Apex) におけるエラーハンドリング について解説します。
1. バッチ処理におけるエラーハンドリングの考え方
1.1. バッチ処理の特徴
Apex バッチ (Database.Batchable
) は、大量データの処理 に適しています。
しかし、一部のレコードでエラーが発生すると、すべてのレコードがロールバックされるわけではない ため、
エラーハンドリングが重要 になります。
バッチ処理の流れ:
-
start()
メソッドで処理対象のレコードを取得 -
execute()
メソッドでバッチごとに処理を実行 -
finish()
メソッドで完了処理(通知やログ記録など)
2. execute()
メソッド内のエラーハンドリング
2.1. try-catch でエラーをキャッチする
✅ OK 例: try-catch で個々のレコードのエラーを処理
global class AccountBatchJob implements Database.Batchable<sObject> {
global Database.QueryLocator start(Database.BatchableContext BC) {
return Database.getQueryLocator('SELECT Id, Name FROM Account');
}
global void execute(Database.BatchableContext BC, List<Account> scope) {
List<Account> updateList = new List<Account>();
for (Account acc : scope) {
try {
if (String.isEmpty(acc.Name)) {
throw new CustomBatchException('アカウント名が空です: ' + acc.Id);
}
acc.Name = acc.Name.toUpperCase();
updateList.add(acc);
} catch (CustomBatchException e) {
ErrorLogService.logError(e, 'AccountBatchJob', 'execute');
}
}
if (!updateList.isEmpty()) {
update updateList;
}
}
global void finish(Database.BatchableContext BC) {
System.debug('バッチ処理完了');
}
}
このコードでは:
-
try-catch
で エラーのあるレコードだけスキップし、正常なレコードを処理 -
ErrorLogService.logError()
を使って エラーログを記録
適用ケース:
一部のエラーは許容しつつ、可能な限り処理を続けたい場合
3. Database.Stateful
を活用してエラーリストを蓄積
バッチ処理では 各 execute()
の処理が独立している ため、
Database.Stateful
を使って エラーリストを蓄積し、最終的にログを出力 する方法もあります。
✅ OK 例: Database.Stateful
を利用したエラーハンドリング
global class AccountBatchJob implements Database.Batchable<sObject>, Database.Stateful {
private List<String> errorMessages = new List<String>();
global Database.QueryLocator start(Database.BatchableContext BC) {
return Database.getQueryLocator('SELECT Id, Name FROM Account');
}
global void execute(Database.BatchableContext BC, List<Account> scope) {
for (Account acc : scope) {
try {
if (String.isEmpty(acc.Name)) {
throw new CustomBatchException('アカウント名が空です: ' + acc.Id);
}
acc.Name = acc.Name.toUpperCase();
} catch (CustomBatchException e) {
errorMessages.add(e.getMessage());
}
}
}
global void finish(Database.BatchableContext BC) {
if (!errorMessages.isEmpty()) {
System.debug('エラーリスト: ' + JSON.serialize(errorMessages));
ErrorLogService.saveErrors(errorMessages); // エラーを保存
}
}
}
このコードでは:
-
Database.Stateful
を使用して、エラーメッセージをfinish()
まで保持 -
finish()
メソッドで エラーログを一括保存
適用ケース:
エラー情報をまとめてログ出力したい場合
4. Database.Savepoint
でトランザクションを制御する
バッチ処理の トランザクション単位でロールバックする 方法として、Database.Savepoint
を活用できます。
✅ OK 例: Savepoint
を活用したリカバリ
global class AccountBatchJob implements Database.Batchable<sObject> {
global Database.QueryLocator start(Database.BatchableContext BC) {
return Database.getQueryLocator('SELECT Id, Name FROM Account');
}
global void execute(Database.BatchableContext BC, List<Account> scope) {
Database.Savepoint sp = Database.setSavepoint();
try {
update scope; // 一括更新
} catch (DmlException e) {
Database.rollback(sp); // エラー時にロールバック
for (Account acc : scope) {
try {
update acc; // 1 レコードずつ更新
} catch (DmlException ex) {
ErrorLogService.logError(ex, 'AccountBatchJob', 'execute');
}
}
}
}
global void finish(Database.BatchableContext BC) {
System.debug('バッチ処理完了');
}
}
このコードでは:
-
Database.Savepoint
で スコープ単位の更新を試行 - 失敗した場合はロールバックし、1 件ずつリトライ
適用ケース:
一括更新時にエラーが発生しても、可能な限り処理を続けたい場合
5. エラー通知を finish()
で送信
バッチ処理でエラーが発生した場合、管理者にメール通知 するのも有効です。
✅ OK 例: Messaging.SingleEmailMessage
でエラーメール通知
global void finish(Database.BatchableContext BC) {
if (!errorMessages.isEmpty()) {
String body = 'バッチ処理でエラーが発生しました。\n' + String.join(errorMessages, '\n');
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(new String[] {'admin@example.com'});
mail.setSubject('【警告】バッチ処理のエラー');
mail.setPlainTextBody(body);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] {mail});
}
}
このコードでは:
-
Messaging.SingleEmailMessage
を使って エラーリストをメールで通知
適用ケース:
エラー発生時に管理者へ即時通知したい場合
まとめ
今回は Apex バッチ処理のエラーハンドリング を解説しました。
try-catch
で個々のレコードのエラーを処理Database.Stateful
でエラーリストを蓄積し、finish()
で一括保存Savepoint
を活用して一括更新のリカバリを行う- エラー通知を
Messaging.SingleEmailMessage
で送信
次の Part 10 では、フューチャーメソッド (Future Methods) や Queueable Apex におけるエラーハンドリング を解説します!