Developer

Salesforceでの非同期処理について

Developer
この記事は約7分で読めます。

こんにちは、アンダーソンです。
今回はセールスフォースにおける非同期処理についてまとめてみました。

スポンサーリンク

非同期処理とは

そもそも非同期処理とはなんでしょうか。
プログラムを呼び出した際に全ての処理を上から下まで実行するのが同期処理
呼び出した関数やメソッドを別のリソースで処理してその処理が完了するのを待つことなく他の処理を始めるのが非同期処理です。

非同期処理の利点としては、

  • ガバナ制限の緩和(SOQLやCPU時間の増加)
  • ユーザが処理を待つ必要がない(バックグラウンドで実行されるため)

などが挙げられます。

非同期処理の種類

Salesforceにおける非同期処理の種類は4種類です。
この際に覚えてしまいましょう。

非同期Apex機能使用するケース
キュー可能 Apex長時間を要する操作を開始し、その ID を取得する場合複雑なデータ型をジョブに渡す場合ジョブをチェーニングする場合
スケジュール済みの Apex特定のスケジュールで実行するために Apex クラスをスケジュールする場合
Apex の一括処理大量のデータを処理する長時間のジョブを複数バッチで実行する必要がある場合 (データベースメンテナンスジョブなど)通常のトランザクションで許容されるよりも大きなクエリ結果が必要になるジョブの場合
future のメソッド長時間を要するメソッドがあり、Apex トランザクションの遅延を防止する必要がある場合外部 Web サービスへのコールアウトを実行する場合DML 操作を分離して混合保存 DML エラーを回避する場合

それぞれにメリットデメリットがありますのでそれぞれ内容をみていきましょう。

@future

非同期処理Apexの中で唯一アノテーションを付与して呼び出すものです。
これはクラスに実装するのではなく、あくまでもメソッド単位で呼び出すことができる
非同期処理になります。

global class FutureTest
{
    @future
    public static void FutureMethod(List<Id> ids)
    {   
         List<Account> accList = [SELECT Id FROM Account WHERE Id IN :ids]
         //処理を書く
    }
}

ケースとしては下記に上げていくようなケースで使うことが多くなると思います。

1.外部Webサービスの呼び出し

Webサービスの呼び出しを行って何か処理を返してもらう際に処理を待つ必要がない場合に使用します。通常の@futureに加えて(callout=true)を宣言したメソッドを実装します。

2.混合DMLエラーの回避

Apexでは同じトランザクション内で同時にDML操作できないsObjectがあります。
→詳しくはこちらです。
その際に一つのsObjectのDML操作を行った後に、非同期処理でもう一つのDML操作を行うことができます。

@futureの制限

  • 24 時間あたりの future メソッドの最大呼び出し数は、250,000 または組織のユーザライセンス数の 200 倍のいずれか大きい方です。他の全ての非同期Apexと共有なので注意しましょう。
  • futureメソッドからfutureメソッドを呼び出すことはできないので注意しましょう
  • static及びvoid型である必要があり、渡せる引数はプリミティブデータ型、プリミティブデータ型の配列及びコレクションである必要があります。

Queueableインターフェース

futureメソッドの強化版のような感じです。
このインターフェースを実装したクラスは進行状況の監視ができる点がfutureメソッドとの大きな違いになります。
さらにQueueableからQueueableの呼び出しも可能なのでさらに時間のかかる処理でも実行することができます。

public class QueueableTest implements Queueable {
    public void execute(QueueableContext context) {
        Account a = new Account(Name='Acme',Phone='080-1111-2222');
        insert a;        
    }
}

executeメソッドは必須で引数にQueueableコンテキストを渡します。
さらにジョブとしてキューに追加するには、

ID jobID = System.enqueueJob(new QueueableTest());

を使用して登録し、設定→Apexジョブから確認することができます。

またHTTPコールアウトもfutureメソッドと同じようにでき、その際はDatabase.AllowsCalloutsを実装しておけばOKです。

Queueableインターフェース制限

  • 一度のトランザクションでSystem.enqueueJobを使って追加できるジョブは50まででガバナ制限なので注意しましょう。
  • ジョブのチェーニング(ジョブからジョブを呼び出す)に関しては制限はありません。
    が、実行中のジョブが呼び出せるジョブは一つのみなので注意しましょう。

Apex の一括処理

いわゆるバッチですね。stratメソッドで操作するレコードを取得し、バッチサイズ(最大200)ずつをexecuteメソッドで処理していき、finishメソッドで必要に応じて後処理を行います。

global class BatchTest implements Database.Batchable<sObject>{
    
    String query;
    
    global BatchTest(String q){
        query = q;
    }
    
    global Database.QueryLocator start(Database.BatchableContext BC){
        return Database.getQueryLocator(query);
    }
    
    global void execute(Database.BatchableContext BC, List<sObject> sObjList){
        for ( sObject s : sObjList ) {
            system.debug(s);
        }
    }
    
    global void finish(Database.BatchableContext BC){
        system.debug('後処理をかく');
    }
}

このような形で書いていきます。
呼び出し方下記のような形でOKです。

String q = 'Select Id FROM Account';
Id batchId = Database.executeBatch(new BatchTest(q), 200);

Apex の一括処理の制限

  • 同時に追加できるキューは5件まで
  • Database.QueryLocator オブジェクトでは最大 5,000 万件のレコードが返されます。5,000 万件以上のレコードが返された場合、一括処理ジョブは即座に終了し「失敗」とマークされます。
  • start、execute、および finish メソッドのコールアウトの最大数は100回まで。
  • futureメソッドを使うもしくは呼び出すことができない

Apex スケジューラ

だいたい一括処理Apexを呼び出すのに使われることが多いです。
決まった時間になったら動き出すように設定ができるため、決まった処理などがある場合に使います。

public class ScheduleTest implements Schedulable {
    public void execute(SchedulableContext SC) {
        Account acc = new Account(); 
    }
}

スケジューラクラスではexecuteメソッドが必須になります。
作成したクラスは設定画面もしくは匿名実行からスケジュールの設定ができます。

CronTrigger オブジェクトおよび CronJobDetail オブジェクトを参照することで今現在のスケジュールの数や実行状況などを把握することができます。

Apex スケジューラの制限

  • 同期コールアウトはできないため@future(callout=true)メソッドを呼び出してコールアウトを行う。一括処理クラスからも呼ぶことは可能。

まとめ

一度実装したらそこまで改修する頻度もなく、頻繁に新しいバッチを作ろう!ってのもなかなかないため、あまり触れる機会はないのですが、非同期処理を知っておけば大量データの扱いなどにも必要な知識なのでぜひ頭に入れておきましょう。

その他の開発に関する記事はこちらです。

Developerも含めた試験問題にチャレンジしてみましょう。

コメント