進行状況の追跡を始めよう
Trailhead のホーム
Trailhead のホーム

非同期 Apex の使用

学習の目的

この単元を完了すると、次のことができるようになります。

  • どのような場合に非同期 Apex を使用するかを理解する
  • future メソッドを使用して Web コールアウトを処理する
  • Batchable インターフェースを使用して大量のレコードを処理する
  • 中間突き合わせが必要な場合に Queueable インターフェースを使用する利点を理解する

非同期を使用する状況

.NET 開発者として、皆さんにはおそらくすでに非同期プログラミングの経験があるでしょう。ここでは、すでに非同期プログラミングの概要とこの種のプログラミングモデルを使用する利点を理解していることを前提とします。一方で、Lightning プラットフォーム上でどのような場合に非同期プログラミングを使用するかについてはまだご存じない場合もあるでしょう。

非同期プログラミングを選択する裏には、通常、次の 3 つの理由があります。

  • 処理するレコード件数が非常に多い。これは、制限が適用される Lightning プラットフォームのマルチテナント環境に特有の理由です。非同期プロセスに関連付けられた制限は、同期プロセスの制限よりも高く設定されます。したがって、数千から数百万件のレコードを処理する必要がある場合、非同期プロセスが最善の策となります。

  • 外部 Web サービスへのコールアウトを行う。コールアウトは処理に長時間かかる可能性がありますが、Lightning プラットフォームではトリガが直接コールアウトすることはできません。

  • 一部の処理を非同期コールにオフロードしてより適切で高速なユーザエクスペリエンスを作成する。すべてを一度に行う必要がありますか? 可能ならば待機させてください。

future メソッド

Web サービスへのコールアウトが必要な場合や、単純な処理を非同期タスクにオフロードする場合、future メソッドを作成することが最良の策である可能性があります。

メソッドを同期から非同期処理に変更するのは非常に簡単です。基本的に、@future アノテーションをメソッドに追加するだけです。それ以外には、メソッドが静的で、void 型のみを返すことを確認してください。たとえば、Web サービスコールアウトを実行するメソッドを作成する場合、次のように行うことができます。

public class MyFutureClass {
    // Include callout=true when making callouts
    @future(callout=true)    
    static void myFutureMethod(Set<Id> ids) {

        // Get the list of contacts in the future method since
        // you cannot pass objects as arguments to future methods
        List<Contact> contacts = [SELECT Id, LastName, FirstName, Email
            FROM Contact WHERE Id IN :ids];

        // Loop through the results and call a method
        // which contains the code to do the actual callout
        for (Contact con: contacts) {
            String response = anotherClass.calloutMethod(con.Id,
                con.FirstName,
                con.LastName,
                con.Email);

            // May want to add some code here to log
            // the response to a custom object
        }
    }
}

作成したら、他の静的メソッドと同様にコールします。非常に簡単です。

future の制限事項

future メソッドは数年前から使用されています。Salesforce 開発者にとって優れた選択肢ですが、欠点がないわけではありません。future メソッドを使用する前に次の制限事項を考慮してください。

  • Apex ジョブ ID が返されないため、実行を追跡できません。
  • パラメータはプリミティブデータ型、プリミティブデータ型の配列、またはプリミティブデータ型のコレクションである必要があります。future メソッドは引数としてオブジェクトを取ることができません。
  • future メソッドをチェーニングしたり、相互にコールしたりすることはできません。

制限を回避するために非同期コールが行われることもありますが、その場合でも制限を考慮する必要があります。「リソース」の「実行ガバナと制限」に関するリンクを参照してください。

Apex 一括処理またはスケジュール済み Apex

もう 1 つの長く使用されている非同期ツールは Batchable インターフェースです。使用される最大の理由は、大量のレコードを処理する必要があるからです。たとえば、最大 5,000 万件のレコードをクリーンアップまたはアーカイブする場合に、Batchable インターフェースを使用します。特定の時刻に一括処理が実行されるようにスケジュールさえできます。

使用するには、クラスで Database.Batchable インターフェースを実装します。start()、execute()、および finish() メソッドも定義します。その後、Database.executeBatch メソッドを使用して一括処理クラスを呼び出せます。たとえば、次のコードでは、組織のすべての取引先を処理し、完了後にメールを送信する Batchable クラスを作成します。

global class MyBatchableClass implements
            Database.Batchable<sObject>,
            Database.Stateful {  

    // Used to record the total number of Accounts processed
    global Integer numOfRecs = 0;

    // Used to gather the records that will be passed to the interface method
    // This method will only be called once and will return either a
    // Database.QueryLocator object or an Iterable that contains the records
    // or objects passed to the job.            
    global Database.QueryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator('SELECT Id, Name FROM Account');                
    }

    // This is where the actual processing occurs as data is chunked into
    // batches and the default batch size is 200.
    global void execute(Database.BatchableContext bc, List<Account> scope) {
        for (Account acc : scope) {
            // Do some processing here
            // and then increment the counter variable
            numOfRecs = numOfRecs + 1;
        }     
    }

    // Used to execute any post-processing that may need to happen. This
    // is called only once and after all the batches have finished.
    global void finish(Database.BatchableContext bc) {
        EmailManager.sendMail('someAddress@somewhere.com',
                              numOfRecs + ' Accounts were processed!',
                              'Meet me at the bar for drinks to celebrate');            
    }

}

その後、次のように匿名コードを使用して一括処理クラスを呼び出せます。

MyBatchableClass myBatchObject = new MyBatchableClass();
Database.executeBatch(myBatchObject);
Note

メモ

この単元ではスケジュール済み Apex について具体的な説明はしませんが、スケジュール済み Apex は Batchable インターフェースに似ています。Schedulable インターフェースを実装し、特定の時刻に Apex を呼び出すために使用できます。詳細は、「非同期 Apex」モジュールを参照してください。

Batchable の制限事項

Batchable インターフェースは優れていますが、他と同様に制限の考慮が必要です。

  • トラブルシューティングが煩雑になることがあります。
  • ジョブはキューに追加され、サーバの可用性に影響されるため、予想よりも時間がかかる場合があります。
  • すでに説明したように制限があります。

Queueable Apex の登場

長い間、future メソッドと Batchable インターフェースは、開発者が非同期処理を行うための主要な手段でした。ただし、すでに説明したようにさまざまな制限があります。開発者によってはこれが問題の原因となっていたため、よりよいソリューションを求める声が大きくなりました。

Winter '15 で、Salesforce はこの要望に Queueable Apex で応えました。これは、future メソッドと Batchable インターフェースの最良の部分すべてを 1 つの素晴らしい非同期ツールにまとめたものです。future メソッドの制限を回避するために時間のかかる Batchable インターフェースを使用せざるを得なかった開発者は、理にかなったツールを手に入れたのです。Queueable Apex は、future メソッドには次の利点をもたらしました。

  • 非プリミティブ型 - クラスは、sObject やカスタム Apex データ型など、非プリミティブデータ型のパラメータ変数を受け入れることができます。
  • 監視 - ジョブを送信すると jobId が返されるため、その ID を使用してジョブを識別し、進行状況を監視できます。
  • ジョブのチェーニング - 実行中のジョブから 2 つ目のジョブを開始することで、2 つのジョブを連鎖的に実行することができます。ジョブのチェーニングは連続的な処理に役立ちます。

これはどのように機能するのでしょうか? よくぞ聞いてくれました。

Queueable Apex には、future メソッドの最良の部分が含まれているため、Apex 一括処理よりも実装がはるかに容易です。Apex 一括処理には、すでに説明したように煩わしい制限があります。しくみを実際に確認するために、future メソッドを使用して Web コールアウトを実行していたサンプルコードを Queueable Apex で実装してみましょう。

public class MyQueueableClass implements Queueable {
    private List<Contact> contacts;

    // Constructor for the class, where we pass
    // in the list of contacts that we want to process
    public MyQueueableClass(List<Contact> myContacts) {
        contacts = myContacts;
    }

    public void execute(QueueableContext context) {
        // Loop through the contacts passed in through
        // the constructor and call a method
        // which contains the code to do the actual callout
        for (Contact con: contacts) {
            String response = anotherClass.calloutMethod(con.Id,
                    con.FirstName,
                    con.LastName,
                    con.Email);

            // May still want to add some code here to log
            // the response to a custom object
        }
    }
}

Queueable Apex は次のように呼び出します。

List<Contact> contacts = [SELECT Id, LastName, FirstName, Email
    FROM Contact WHERE Is_Active__c = true];
Id jobId = System.enqueueJob(new MyQueueableClass(contacts));

もうひとこと...

Spring '15 では、Queueable インターフェースに加えて Apex Flex キューも導入されました。これにより同時一括処理が 5 つという制限が撤廃されました。また、開発者がキュー内にあるジョブの順序を監視して管理できるようになりました。詳細は、「リソース」のリンクを参照してください。

このモジュールでは、.NET 開発者に Lightning プラットフォームで使用可能な非同期オプションを紹介しました。テスト、ジョブの監視、ベストプラクティスなど、このトピックに関する詳細は、「非同期 Apex」モジュールを参照してください。

リソース