今回は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クラスを返却し、コールバックメソッドで画面遷移やメッセージ出力を行う


コメント