Memos About Salesforce

Salesforceにハマってたこと!

Salesforce Apex callout in futrue method process order

こんにちは、管理人の@Salesforce.Zです。

Salesforceの奥が深いですね。 開発においては、外部 Web Service から取得した結果に基いてセールスフォース内のレコードを作成/更新するケースが多々あります。 しかしながら、同じトランザクション内で DML(Insert/Update/Upsert/Delete)発行後にコールアウトを行なう事はでません。

今回非同期メソッドの中で、DMLとhttp コールアウトの順番について記事を起こします。 なぜなら、間違えたら、エラーになるからです。

読んだら得ること

★ 非同期メソッドの中でコールアウトエラーの解消

目次

問題

futrue methodを使い、データ登録をした。 データ登録後に、つまりDMLステートメントCRUD)を発行後に、httpメソッドで、コールアウトを実行すると下記のエラーになります。 「You have uncommitted work pending. Please commit or rollback before calling out

コード例

global with sharing class yourclass{
    @future(callout=true)
    private static void followAsynJob(String requestBody){
        try{
              //➀DML operation
              Account acc = new Account();
              acc.Name = 'test';
              insert acc;
              //②call out
              String params = 'params';
              excuteCallout(params );

        }catch(DmlException e){
            System.debug('The following exception has occurred: ' + e.getMessage());
        }
    }
    private static Map<String, String> excuteCallout(String params){
        Map<String, String> userMap = new Map<String, String>();
        Map<String, Object> result;
        String authorizationHeader = 'Bearer {accessToken}';
        
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint('https://api.sample/' + params);
        request.setHeader('Authorization', authorizationHeader);
        request.setMethod('GET');
        HttpResponse response = http.send(request);
        // Parse the JSON response
        if (response.getStatusCode() == 200) {
            
        } else {
            System.debug('リクエスト失敗' + response.getStatusCode() + ' ' + response.getStatus());
        }
        return userMap;
    }
}

上記のコードのように、➀がDML実行、②がcallout実行となり、これは「You have uncommitted work pending. Please commit or rollback before calling out」エラーになります。

原因は公式ドキュメントを参照してください。

対策

回避策としては、下記のサンプルコードのように、トランザクションを分けるように実装することで 後半のHTTPコールアウト後の更新処理が実行可能となります。

トランザクションを分けて実装するだが、エラーとなる順番➀と②を逆にすれば、解消できます。