【Salesforce】Apexバッチで発生したガバナ制限エラーを通知する方法

2023-08-15

やりたいこと

Apexバッチ(一括処理)で、ガバナ制限エラーが発生した場合にユーザへ通知したい。

背景

ApexのTry-Catchでは、Salesforce Platform 内部エラーや、ガバナ制限に達したために発生する LimitExceptions などをキャッチできない。

解決方法のポイント

・Apex 一括処理にて、Salesforce Platform 内部エラーまたはガバナ制限に達したために発生したときにプラットフォームイベントを起動します。
・イベントをリスンするクライアントとして、RaisesPlatformEventsオブジェクトのApexトリガを作成します。
・イベンドメッセ-ジから詳細なエラーの追跡情報を取得して、カスタムApexロジックにてメール送信します。

使用する機能

・Database.RaisesPlatformEvents インターフェース
・BatchApexErrorEventオブジェクトとトリガ

バッチの作成

★ポイント:プラットフォームイベントを起動するには、Apex 一括処理クラス宣言で Database.RaisesPlatformEvents インターフェースを実装する必要があります。
下記の例では、発行される DML ステートメントの合計数を、151以上になるように記載し、ガバナ制限の例外を発生させています。

 global class ContactCreateBatch implements Database.Batchable<sObject>,Database.RaisesPlatformEvents{
    global Database.QueryLocator start(Database.BatchableContext BC){
        return Database.getQueryLocator('Select id,name from Account Limit 1000');
    }

    global void execute(Database.BatchableContext BC, List<sObject> scope){
        Integer recordIndex=0;
        for(sobject s : scope){
            Account acc =(Account)s;
            for(Integer i = 0; i <= 200; i++){
                Contact con = new Contact();
                con.AccountId = acc.id;
                con.LastName = 'TEST';
                Database.SaveResult sr = Database.insert(con);
            }
        }
    }

    global void finish(Database.BatchableContext BC){}
}

BatchApexErrorEventのApexトリガ作成

★ポイント:RaisesPlatformEventsオブジェクトにイベントが登録される発火するApexトリガを作成します。
下記の例では、一括処理トランザクションで失敗した取引先IDや、発生した例外内容などを、メール通知しています。

trigger BatchApexErrorEventTrigger on BatchApexErrorEvent (after insert) {
    Set<Id> asyncApexJobIds = new Set<Id>();
    for(BatchApexErrorEvent evt:Trigger.new){
        asyncApexJobIds.add(evt.AsyncApexJobId);
    }

    Map<Id,AsyncApexJob> jobs = new Map<Id,AsyncApexJob>(
        [SELECT id, ApexClass.Name FROM AsyncApexJob WHERE Id IN :asyncApexJobIds]
    );

    String subject = '[一括処理でエラーです]{0}';
    String body = '';
    for(BatchApexErrorEvent evt : Trigger.new){
        subject = String.format(subject, new List<String>{jobs.get(evt.AsyncApexJobId).ApexClass.Name});
        body += 'ExceptionType:'+ evt.ExceptionType+ '\n';
        body += 'JobScope:'+ evt.JobScope+ '\n';
        body += 'Message:'+ evt.Message+ '\n';
        body += 'Phase:'+ evt.Phase+ '\n';
        body += 'StackTrace:'+ evt.StackTrace+ '\n';
    }

    Set<String> mailSet = new Set<String>();
    mailSet.add('*****@nddhq.co.jp');
    String[] strAry = new List<String>(mailSet);
    Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
    mail.setToAddresses(strAry);
    mail.setSubject(subject);
    mail.setPlainTextBody(body);
    Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}

メール通知結果

下記は、上記トリガ処理で送信されたメールです。自動化プロセスが送信元になっています。

まとめ

本投稿では、メール通知処理を記載しました。
他にもBatchApexErrorEventトリガ内に、一括処理でエラーとなったレコードIDを保持しているため、当該エラーレコードに何かしらの更新をするなどの応用も可能ですね。

関連記事

Apex 一括処理からのプラットフォームイベントの起動
BatchApexErrorEvent
イベント登録のデバッグログの設定