未処理の例外があるとDMLは行われない
LWCから呼び出されたApexでエラーが発生した時、AuraHandledExceptionをスローしてJavaScriptでエラーを処理することがあります。例外をスローするので、当然ロールバックが起きます。そのため、たとえばエラーログをレコードとして残したい時でも、通常のDML操作ではレコードが作成されません。また、futureメソッドも実行されません。
public class SampleController {
@AuraEnabled
public static void doSomething() {
try {
// 処理
} catch (Exception e) {
// ロールバックされるためレコードが作成されない。
insert createLog(e);
throw new AuraHandledException(e.getMessage());
}
}
private static Log__c createLog(Exception e) {
return new Log__c(
Message__c = e.getMessage(),
DetailMessage__c = e.getStackTraceString()
);
}
}
public class SampleController {
@AuraEnabled
public static void doSomething() {
try {
// 処理
} catch (Exception e) {
// トランザクションがロールバックされるとFutureメソッドは処理されない。
writeLogAsync(e.getMessage(), e.getStackTraceString());
throw new AuraHandledException(e.getMessage());
}
}
@Future
private static void writeLogAsync(String message, String detail) {
insert new Log__c(
Message__c = message,
DetailMessage__c = detail
);
}
}
例外を投げつつレコードを作成する場合はプラットフォームイベントを使用する
プラットフォームイベントは、すぐに公開するか、トランザクションが正常に終了した後に公開するかを選択することができます。すぐに公開を選択することで、処理されない例外が発生してロールバックが起きてもイベントトリガーを介してレコードを保存することができます。ただし、プラットフォームイベントには1日あたりのリミットがあるため、大量のイベントを発生させる場合は注意が必要です。
1. プラットフォームイベントを作成する
「設定 > プラットフォームイベント > 新規プラットフォームイベント」からプラットフォームイベントを作成します。このとき、公開動作は「すぐに公開」を選択します。作成後にカスタム項目も作成します。
2. プラットフォームイベントトリガーフローを作成する
「設定 > フロー > 新規フロー」でプラットフォームイベントトリガーフローを選択して、プラットフォームイベントが登録された時にDML操作を行うフローを作成します。
3. Apexでプラットフォームイベントを公開する
public class SampleController {
@AuraEnabled
public static void doSomething() {
try {
// 処理
} catch (Exception e) {
// ロールバックしてもイベントが公開される
EventBus.publish(createLogEntryEvent(e));
throw new AuraHandledException(e.getMessage());
}
}
private static LogEntryEvent__e createLogEntryEvent(Exception e) {
return new LogEntryEvent__e(
Message__c = e.getMessage(),
DetailMessage__c = e.getStackTraceString()
);
}
}
Appendix
プラットフォームイベントを公開するApexのテスト
下記の二通りあります。
-
Test.stopTest()
の後にAssertメソッドを実行する -
Test.getEventBus().deliver();
の後にAssertメソッドを実行する
@IsTest
public class SampleControllerTest {
@IsTest
static void testDoSomething() {
try {
Test.startTest();
SampleController.doSomething();
Test.stopTest();
} catch (Exception e) {
Test.getEventBus().deliver();
Assert.isInstanceOfType(e, AuraHandledException.class);
List<Log__c> result = [SELECT Id FROM Log__c];
Assert.areEqual(1, result.size(), 'ログサイズ');
}
}
}
Deliver Test Event Messages | Salesforce Developers