Loading
Salesforce から送信されるメールは、承認済ドメインからのみとなります続きを読む

Exception.getStackTraceString を使用している場合、非同期コンテキストでエラーメッセージが表示されない

公開日: Jul 25, 2019
説明
Exception.getStackTraceString() が使用されている管理パッケージがあります。コードが同期してコールされると、最初に非管理コンテキストから呼び出された管理パッケージクラスから非管理クラスがコールされて例外が発生します。このようなコンテキストでは、完全なエラーメッセージが表示されます。

ただし、同じ管理クラスが非同期操作でスケジュールされている場合、管理パッケージのコンテキストで非同期操作が開始されるため、エラーの詳細には括弧 () のみが表示され、エラーメッセージが表示されません。

以下のコードを参照してください。

Apex クラス Thrower (管理パッケージの一部):
global class Thrower implements Queueable {
    
    String namespacePrefix;
    String className;
    
    global Thrower(String namespacePrefix, String className) {
        this.namespacePrefix = namespacePrefix;
        this.className = className;
    }
    
    global void execute(QueueableContext context) {
        try {
            Type reflector = Type.forName(this.namespacePrefix, this.className);
            Object impl = reflector.newInstance();
        } catch (Exception e) {
            throw new StringException(e.getStackTraceString());
        }
    }
    
}

Apex クラス ThrowerTest (管理パッケージの一部):
@IsTest class ThrowerTest {
    
    public class Impl {
        public Impl() {
            throw new StringException('got here');
        }
    }
    
    static testmethod void testGood() {
        
        
        String namespacePrefix = '';
        String className = Impl.class.getName();
        
        try {
           
            Test.startTest();
            Queueable job = new Thrower(namespacePrefix, className);
            System.enqueueJob(job);
            Test.stopTest();
        } catch (Exception e) {
           
            System.assertNotEquals('()', e.getMessage(), 'wrong message');
        }
    }
    
}

Apex クラス ThrowerService (管理パッケージの外部):
global class ThrowerService { 
global ThrowerService() { 
throw new StringException('got here'); 
} 
}
解決策
これは設計どおりの動作です。主な要因は、呼び出し元ユーザの実行コンテキストです。異なる結果が生成される同期実行と非同期実行の違いを次に示します。

同期:
  •  この例では、new MANAGED_NAMESPACE.Thrower('', 'ThrowerService').execute(null); のように匿名実行エントリポイントで管理パッケージオブジェクトをインスタンス化します。 
  •  匿名実行するユーザはあなたです。名前空間が空白になっていることに注意してください。
  •  execute メソッドが指定のとおりに起動し (呼び出し元ユーザはあなた)、ローカルクラスタイプをインスタンス化しようとします。
  •  ここまでは、実行の名前空間スタックは <blank> -> MANAGED_NAMESPACE -> <blank> のようになっています。
  •  この例では、非管理クラスで例外が発生します。<blank> の名前空間で例外が発生していることに注意してください。
  •  この例外のスタックトレースは、呼び出し元ユーザのコンテキストで名前空間を記録することが許可されている場合にのみ実行されます。この例では、例外が <blank> 名前空間内で発生しているため実行されます。

非同期:
  • 非同期操作でも匿名の呼び出し元ユーザはあなたですが、管理パッケージからキュー可能なクラスをキューに追加する時点までになります。
  • 非同期ジョブの実行が開始されると、その個別の新しい操作の呼び出し元ユーザのコンテキストは管理パッケージになります。
  • この時点で名前空間の実行スタックは MANAGED_NAMESPACE -> <blank> のようになっています。
  • スタックをエンドユーザ (この例ではパッケージの登録者が使用できる Apex ジョブログ) に公開するかどうかを評価する場合、誰がこのトランザクションを開始したのかが確認されます。この例では、トランザクションは管理名前空間から開始されています。そのため、管理名前空間で問題が発生すると、例外が <blank> 名前空間で生成/発生していても、管理パッケージ名前空間内にしか公開されません。

メモ:
  •  管理パッケージのデバッグログが有効になっている場合、完全なスタックトレースが結果に表示されます。
  •  スタックトレースの難読化や非表示はすべて、パートナーが独自実装の詳細を公開しないように保護するためのものです。
  •  管理パッケージでトランザクションが開始された場合、情報を再発生させて登録ユーザに戻すのではなく、管理パッケージ内ですべての例外処理および解決策を実行する必要があります。
  • 他の解決策として、トラブルシューティングが必要な場合に登録者組織で一時的にログを有効にするという方法もあります。
ナレッジ記事番号

000383964

 
読み込み中
Salesforce Help | Article