非同期でApexは@futureメソッドを使用した方法がスタンダードですが、今回は割と最近出たキュー可能Apexを使った方法について取り上げたいと思います。
余談だけど、キューって英語で書くと「きゅーうえうえ」って書くからなんか違和感あるよね。
使用方法
キュー可能なApexは@futureと同じ、非同期で実行されるApexクラスとなります。
使用方法としては、Queueableインタフェースを使用するだけです。
Queueableインタフェースを使用するとexecuteメソッドが必須となるので、executeメソッド内に非同期処理するコードを記述します。
実行する場合は、System.enqueueJobメソッドを使用して、引数にQueueableインタフェースを実装したクラスを渡すことで、非同期でexecuteが実施されます。
@futureとの違いは?
でも、@futureアノテーションでの非同期実行があるのに、何でキュー可能Apexを使う必要があるのでしょうか?
@futureより優れている点は以下の3つです。
様々な形の引数が使用できる
@futureメソッドでの非同期実行でも引数を渡せますが、渡せる引数はプリミティブ型(IntegerやStringなど)かそのリスト型という単純なものしか使用できませんでした。
キュー可能Apexはexecuteに直接パラメータを渡すことはできませんが、コンストラクタでパラメータを渡すことが可能で、sObject型やクラスなどの複雑なパラメータも渡すことが可能です。
ジョブ監視ができる
System.enqueueJobメソッドで実行した時に、AsyncApexJobのレコードIDを返却します。
実施中は非同期ですが、このレコードIDを使って実行状況を追跡することができます。
以下SOQLを実行することで、ジョブの監視ができます。
JobTypeには「Queueable」が入り、Statusには「Failed」や「Completed」などの実行状況を表すステータスが入ります。
ジョブ監視用のSOQL
Select Id, JobType, Status From AsyncApexJob Where Id = 'レコードID'
チェーニングができる
これが、一番の特徴かもしれません。
executeメソッド内で、さらにSystem.enqueueJobメソッドを使用して、キュー可能Apexからキュー可能Apexを実行することができます。
これをチェーニングと呼びます。
チューニングでは無いので注意!
鎖のチェーンから来てるのでチェーニングですね。
コード例
実際にコードを記述しました。チェーニングを使って実現します。
まずは、最初に呼ばれるApex。
executeの中でやる処理は適当です。
FirstJob.cls
public class FirstJob implements Queueable {
public void execute(QueueableContext context) {
for(Integer i = 0; i < 100; i++){
System.debug('Hoge First');
}
System.enqueueJob(new SecondJob());
}
}
次に、SecondJob。こちらは、Httpコールアウトを使用しています。
SecondJob.cls
public class SecondJob implements Queueable,Database.AllowsCallouts {
public void execute(QueueableContext context) {
for(Integer i = 0; i < 10; i++){
//HTTPリクエストの作成
HttpRequest req = new HttpRequest();
req.setEndpoint('http://www.apexdevnet.com');
req.setMethod('GET');
//HTTPリクエストの送信
Http http = new Http();
HttpResponse res = http.send(req);
//レスポンスチェック
if (res.getStatusCode() == 200) {
//成功時に実行したい処理
} else {
System.debug('Callout failed: ' + res);
}
}
}
}
キュー可能Apexもバッチ同様、コールアウトを使用する時は、Database.AllowsCalloutsインタフェースが必要なので、使う場合は忘れずに。
テストクラスの書き方
テストクラスを記述する場合は、バッチクラス同様、Test.startTest()とTest.stopTest()の間にSystem.enqueueJobメソッドを挟めばOK。
FirstJobTest.cls
@isTest private class FirstJobTest { @IsTest static void jobTest() { Test.startTest(); System.enqueueJob(new FirstJob()); Test.stopTest(); } }
FirstJobのテストクラスはこのように書けばOK・・・ではないんです。
このテストクラスを実行するとこんなエラーが発生します。
テストクラスでは、チェーニングができないんですね。
このエラーを回避するには、テスト実行時にはチェーニングしないようにする制御が必要となります。
コードでは、Test.isRunningTest()を使用して、テスト実行時はチェーニングを回避するようにします。
FirstJob.clsのチェーニング部分
System.enqueueJob(new SecondJob());
これを、このように修正します。
if(!Test.isRunningTest()){ System.enqueueJob(new SecondJob()); }
テストの時に、チェーニングを飛ばしているので、カバレッジは100%にはなりません。
まとめ
- キュー可能ApexはQueueableインタフェースを使用
- 複雑な引数、ジョブ監視、チェーニングが使用可能のため、@futureメソッドより用途が広い
- テストクラス内でのチェーニングは使用不可
コメント