Part 7: エラーハンドリングの設計パターン (エラーログ管理・リトライ機構)
前回は テストクラスでのエラーハンドリング と カスタム例外の活用 について解説しました。
今回は 実際の運用で役立つエラーハンドリングの設計パターン として、
エラーログの管理 と リトライ機構 (再試行) の実装 を解説します。
1. エラーログ管理の重要性
1.1. なぜエラーログが必要か?
Apex の処理がエラーで停止すると、管理者や開発者に通知されない限り問題に気づきにくい です。
そのため、エラーログを記録し、エラーを監視できる仕組みを作ることが重要 です。
1.2. エラーログの作成
Salesforce には カスタムオブジェクト を作成してエラーを記録するのが一般的です。
以下のような ErrorLog__c
オブジェクト を作成しましょう。
項目名 | API名 | 型 | 説明 |
---|---|---|---|
エラーメッセージ | Message__c |
長いテキスト | 発生したエラー内容 |
クラス名 | ClassName__c |
テキスト | 例外が発生したクラス名 |
メソッド名 | MethodName__c |
テキスト | 例外が発生したメソッド名 |
行番号 | LineNumber__c |
数値 | エラー発生行 |
スタックトレース | StackTrace__c |
長いテキスト | 詳細なエラー情報 |
発生日時 | OccurredAt__c |
日時 | エラー発生時刻 |
1.3. エラーログを記録する共通メソッド
エラーを ErrorLog__c
に記録するメソッドを作成します。
こうすることで、どこでエラーが発生しても統一的にログを記録できます。
✅ OK 例: ErrorLogService
クラス
public class ErrorLogService {
public static void logError(Exception e, String className, String methodName) {
try {
ErrorLog__c log = new ErrorLog__c();
log.Message__c = e.getMessage();
log.ClassName__c = className;
log.MethodName__c = methodName;
log.LineNumber__c = e.getLineNumber();
log.StackTrace__c = e.getStackTraceString();
log.OccurredAt__c = System.now();
insert log;
} catch (Exception ex) {
System.debug('ログ記録中にエラー発生: ' + ex.getMessage());
}
}
}
1.4. 例外発生時にログを記録
例外が発生したときに、エラーログを記録するように try-catch
を実装 します。
✅ OK 例: AccountService
クラス
public class AccountService {
public static void createAccount(Account acc) {
try {
insert acc;
} catch (DmlException e) {
ErrorLogService.logError(e, 'AccountService', 'createAccount');
throw e;
}
}
}
1.5. エラーログを可視化
エラーログを管理するには、カスタムレポートやダッシュボードを作成 し、
管理者がエラーを確認できるようにするとよいでしょう。
また、フローやプロセスビルダーでエラー発生時に通知を送る のも効果的です。
2. リトライ機構 (再試行) の実装
2.1. なぜリトライが必要か?
Salesforce の API 制限や一時的なネットワークエラーのために、
DML 操作や外部システムとの通信が一時的に失敗することがあります。
特に以下のようなケースでは、リトライ機構を実装することで処理の成功率を高められます。
-
DmlException
: ガバナ制限 による DML 失敗 -
CalloutException
: 外部 API の一時的な障害 によるコールアウト失敗 -
QueryException
: SOQL クエリの一時的な制限 によるエラー
2.2. 再試行の基本設計
一定回数までリトライし、それでも失敗したらエラーログに記録する 形が一般的です。
2.3. DML 操作のリトライ
✅ OK 例: DMLHelper
クラス
public class DMLHelper {
public static void insertWithRetry(SObject record, Integer maxRetries) {
Integer attempts = 0;
Boolean success = false;
while (attempts < maxRetries && !success) {
try {
insert record;
success = true;
} catch (DmlException e) {
attempts++;
if (attempts == maxRetries) {
ErrorLogService.logError(e, 'DMLHelper', 'insertWithRetry');
throw e; // 最大リトライ回数に達した場合は例外をスロー
}
System.debug('DML 失敗、リトライ ' + attempts + ' 回目');
}
}
}
}
このメソッドは DML 操作が失敗した場合に最大 maxRetries
回までリトライ します。
それでも失敗した場合は、エラーログを記録して例外をスロー します。
2.4. 外部 API コールアウトのリトライ
外部システムとの連携では、ネットワーク障害やタイムアウト が発生することがあります。
CalloutException
が発生した場合に、一定回数リトライする 実装をします。
✅ OK 例: CalloutHelper
クラス
public class CalloutHelper {
public static String makeCallout(String endpoint, Integer maxRetries) {
Integer attempts = 0;
Boolean success = false;
String response = '';
while (attempts < maxRetries && !success) {
try {
Http http = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint(endpoint);
req.setMethod('GET');
HttpResponse res = http.send(req);
if (res.getStatusCode() == 200) {
response = res.getBody();
success = true;
} else {
throw new CalloutException('HTTPエラー: ' + res.getStatusCode());
}
} catch (CalloutException e) {
attempts++;
if (attempts == maxRetries) {
ErrorLogService.logError(e, 'CalloutHelper', 'makeCallout');
throw e;
}
System.debug('Callout 失敗、リトライ ' + attempts + ' 回目');
}
}
return response;
}
}
このメソッドは 外部 API のコールアウトが失敗した場合に最大 maxRetries
回までリトライ します。
まとめ
今回は エラーハンドリングの設計パターン として、
エラーログ管理 と リトライ機構 について解説しました。
ErrorLog__c
カスタムオブジェクトでエラーを管理ErrorLogService
で例外を一元的に記録- DML 操作・API コールアウトのリトライ機構を実装
- リトライ回数を制限し、最大回数を超えたらログを記録
次の Part 8 では、トリガー (Trigger) におけるエラーハンドリングとリカバリ方法 を解説します!