今回はContinuationクラスについて取り上げます。
Continuationクラスとは
Continuationは日本語に訳すと継続や存続などを意味します。
よくゲームとかで使うコンティニューの名詞形ですね。
これをApexクラスの中で使用できるのですが、使い方についてはまだ浸透されていません。
ContinuationクラスはVisualforceページから非同期コールアウトを使用する時に、コールアウトの時間が長くなる時に使用されます。
Spring15からの機能で、こちらに簡単な処理の流れなも載っています。
従来のHTTPコールアウトに比べると、
- 一度に3つのHTTPコールアウトが実施できる
- 非同期を実行して終わりでなく、コールアウト終了後にApexのアクションを実施できる
- 長時間要求の同時実行数(同時実行10まで)の制限の対象とならない
など、イイことずくめの機能であり、覚えておいて損はない機能だと思います。
使用例
では、使い方について、今回はVisualForceページとボタンを押した時に、外部サーバへHTTPコールアウトする処理を作成します。
まずは、VisualForceページから
ContinuationTest.page
<apex:page controller="ContinuationController" showChat="false" showHeader="false"> <apex:form > <!-- ボタン押下でコールアウトを実行し、結果を出力 --> <apex:commandButton action="{!startRequest}" value="Start Request" reRender="result"/> </apex:form> <!-- コールアウト結果を出力 --> <apex:outputText id="result" value="{!result}" /> </apex:page>
次はApexクラス。こちらに、Continuationクラスの仕組みを作ります。
ContinuationController.cls
public with sharing class ContinuationController { // リクエストラベル public String requestLabel; // コールアウト結果のプロパティ public String result {get;set;} // エンドポイント private static final String LONG_RUNNING_SERVICE_URL = 'https://th-apex-http-callout.herokuapp.com/animals'; // アクションメソッド public Object startRequest() { // Continuationクラスを作成し、タイムアウトを設定 Continuation con = new Continuation(40); // コールバックメソッド名を設定 con.continuationMethod='processResponse'; // HTTPリクエストを作成 HttpRequest req = new HttpRequest(); req.setMethod('GET'); req.setEndpoint(LONG_RUNNING_SERVICE_URL); // ContinuationクラスにHTTPリクエストを追加 this.requestLabel = con.addHttpRequest(req); // PageReferenceの代わりにContinuationクラスを返却 return con; } // コールバックメソッド public Object processResponse() { // レスポンスラベルをキーとして、レスポンスを取得する HttpResponse response = Continuation.getResponse(this.requestLabel); // Set the result variable that is displayed on the Visualforce page this.result = response.getBody(); // VisualForceページの画面遷移、re-renderであればnullを返却 return null; } }
Apexクラスのアクションの流れを簡単に説明しますと、
Continuationクラスを使用しない、従来のHTTPコールアウトを使用した処理は、
- VisualForce上からボタン押下
- ApexクラスコントローラアクションのトランザクションでHTTPリクエストを作成
- トランザクション内でコールアウトを実行し、レスポンスを取得
- レスポンスに応じてメッセージ出力や画面遷移を行う
といった感じです。
この時、3のコールアウトの際に、サーバの応答が遅い状態だと、トランザクション内での処理がストップしてしまい、画面はフリーズし、同時に実行されるHTTPコール数が消費されサーバ側の制限に引っかかりやすくなり、設計上よろしくない作りとなってしまいます。
次にContinuationクラスを使用した場合、コールアウト側は非同期となり、タイミングによって様々なプロセスが動きます。
- VisualForce上からボタン押下
- ApexクラスコントローラアクションのトランザクションでHTTPリクエストを作成
- ContinuationクラスにHTTPリクエストを追加(この時、リクエストラベルが生成)
- Continuationクラスを返却してアクションメソッド終了
ボタン押下時のアクションは一旦ここで切れます。
この時に、非同期でContinuationによるHTTPコールアウトが裏で実行されます。
その時のContinuation側の処理はこのようになります。
- リクエストラベルを使用して、指定したHTTPリクエストのレスポンスを取得(複数あれば複数回実施)
- レスポンスに応じてメッセージ出力や画面遷移を行う
このように、従来のHTTPコールアウト処理を分断した形になります。
複数HTTPコールアウトで確認
今後はApexクラスを少し修正してみます。
ContinuationController.cls
public with sharing class ContinuationController { // リクエストラベル public String requestLabel; // コールアウト結果のプロパティ public String result {get;set;} // エンドポイント private static final String LONG_RUNNING_SERVICE_URL = 'https://th-apex-http-callout.herokuapp.com/animals'; // アクションメソッド public Object startRequest() { // Continuationクラスを作成し、タイムアウトを設定 Continuation con = new Continuation(40); // コールバックメソッド名を設定 con.continuationMethod='processResponse'; // HTTPリクエストを作成 HttpRequest req = new HttpRequest(); req.setMethod('GET'); req.setEndpoint(LONG_RUNNING_SERVICE_URL); // ContinuationクラスにHTTPリクエストを追加 this.requestLabel = con.addHttpRequest(req); // 2つめのHTTPリクエストを作成 HttpRequest req2 = new HttpRequest(); req2.setMethod('POST'); req2.setEndpoint(LONG_RUNNING_SERVICE_URL); req2.setHeader('Content-Type', 'application/json;charset=UTF-8'); req2.setBody('{"name":"mighty moose"}'); // ContinuationクラスにHTTPリクエストを追加 this.requestLabel2 = con.addHttpRequest(req2); // PageReferenceの代わりにContinuationクラスを返却 return con; } // コールバックメソッド public Object processResponse() { // 1つめのHTTPコールアウトのレスポンスを取得 HttpResponse response = Continuation.getResponse(this.requestLabel); String ret1 = response.getBody(); // 2つめのHTTPコールアウトのレスポンスを取得 response = Continuation.getResponse(this.requestLabel2); String ret2 = response.getBody(); this.result = ret1 + ret2; // VisualForceページの画面遷移、re-renderであればnullを返却 return null; } }
このように、複数のHTTPリクエストを使用して実行してみます(最大3つまで追加できます)。
リクエストラベルを使ってのレスポンス処理が必要になりますが、複数コールアウトでGET・POSTが混じったものも問題なく実行できました。
まとめ
- ContinuationクラスはHTTPコールアウトを使用するVisualForceページで使用する
- Continuationクラスには最大3つのHTTPリクエストが登録でき、非同期実行のため同時実行数にカウントされない
- アクションメソッド側でContinuationクラスを返却し、コールバックメソッドで画面遷移やメッセージ出力を行う
コメント