EJBタイマーサービスでは、以下のようなタイマーを作成し、任意の時刻にEJBコンテナからコールバック処理を実行させることができます。
一定時間経過後にコールバック
一定時間経過後にコールバック、その後定期的にコールバック
指定日時にコールバック
指定日時にコールバック、その後定期的にコールバック
以下について説明します。
基本機能
タイマーは、javax.ejb.TimerServiceインタフェースのcreateTimerメソッドを実行して生成します。createTimerメソッドの引数に実行時刻や実行間隔を指定します。EJBタイマーサービス(javax.ejb.TimerServiceインタフェースの実装)は、以下の方法で取得できます。
EJBコンテナより渡されるEJBコンテキストのgetTimerServiceメソッドを実行する。
javax.ejb.TimerService型のフィールドに@Resourceアノテーションを付与する。
生成したタイマーをキャンセルするには、生成したタイマーのcancelメソッドを実行します。
タイマー生成時に指定した時刻に、EJBタイマーサービスより各Enterprise Beanのタイマーコールバックメソッドを実行します。タイマーコールバックメソッドは、以下のいずれかで定義できます。
コールバックしたいメソッドに@Timeoutアノテーションを定義する。
Beanクラスがjavax.ejb.TimedObjectインタフェースを実装し、ejbTimeoutメソッドを定義する。
deployment descriptor(ejb-jar.xml)ファイルのtimeout-methodタグにタイマーコールバックメソッド名を定義する。
タイマーは、データベースに永続化します。IJServerクラスタ起動時にタイマー情報をデータベースから取得するため、以下の操作によりIJServerクラスタプロセスが再起動されると、タイマーが自動的に回復します。
IJServerクラスタが異常終了後、プロセスが自動再起動された場合
IJServerクラスタを再起動した場合
タイマーの永続化について
タイマーを使用する場合、永続化のためのデータベースが必要です。使用するデータベースを用意してください。
タイマーをトランザクション内で生成すると、トランザクションの終了時にトランザクションのステータスに従って、タイマー情報の登録もコミットまたはロールバックされます。そのため、タイマーを使用するトランザクション内で別のJDBCデータソースやJMSリソースをアクセスする場合、グローバルトランザクションに対応するデータソース(XADataSource)を使用する必要があります。
グローバルトランザクションを使用すると性能のオーバーヘッドがあるため、タイマー生成処理やコールバック処理でJDBCのAPIまたはJPAを使用してデータベースにアクセスする場合には、タイマー永続化にも同じデータソースを使用することを推奨します。
以下の表にデータベースに用意するテーブルを示します。テーブル名は、「EJB__TIMER__TBL」にしてください。
カラム名 | データ型のJDBCタイプ | データの長さ(最大値) | 制約 |
---|---|---|---|
TIMERID | VARCHAR | 46 + [サーバーインスタンス名の長さ] + [IJServerクラスタ名の長さ] | PRIMARY KEY |
OWNERID | VARCHAR | [サーバーインスタンス名の長さ] | NULL |
CREATIONTIMERAW | BIGINT | 19桁(9223372036854775807) | NOT NULL |
BLOB | LONGVARBINARY | プライマリキーと情報オブジェクトのバイナリサイズによる | NULL |
CONTAINERID | BIGINT | 19桁(9223372036854775807) | NOT NULL |
STATE | INTEGER | 1桁 | NULL |
PKHASHCODE | INTEGER | 10桁(2147483647) | NULL |
INTERVALDURATION | BIGINT | 19桁(9223372036854775807) | NOT NULL |
INITIALEXPIRATIONRAW | BIGINT | 19桁(9223372036854775807) | NOT NULL |
LASTEXPIRATIONRAW | BIGINT | 19桁(9223372036854775807) | NOT NULL |
JDBCタイプとDBMSのSQLデータ型のマッピングについては、JDBCドライバのマニュアルを参照してください。
タイマーサービスの永続化は、以下のデータベースをサポートします。
アプリケーション開発時やサンプル動作のためにJava DBデータベースも使用できますが、動作保証されません。
Oracle
SQL Server
Java EE共通ディレクトリのdatabasesディレクトリにタイマー用のテーブルを用意したJava DBデータベースが格納されています。IJServerクラスタを起動する前に、このデータベースをasadminコマンドのstart-databaseサブコマンドにより起動してください。
上記データベースを利用するためのデフォルトデータソースは、「jdbc/__TimerPool」です。
EJBタイマーサービス用のデータベースを使用するために、リソース(データソース)を運用するIJServerクラスタのターゲットに指定し、リソースの状態を「有効」に設定してください。リソースのターゲットを変更する手順については「5.13.7 リソースを利用するターゲットを選択する場合の手順」を、リソースの状態を変更する手順については、「5.13.6 リソースの状態を変更する場合の手順」を参照してください。
サーバーインスタンス名でレコードを区別するため、複数のサーバーインスタンスから同じテーブルを使用できます。ただし、複数のマシンから同じテーブルを使用する場合には、サーバーインスタンス名が重複することがあるため、サーバーインスタンス起動時に別のマシンのサーバーインスタンスで生成されたタイマーが実行される可能性があります。この場合には、サーバーインスタンス名が重複しないように注意してください。
データベースごとのテーブル生成のDDLファイルが、以下に格納されています。DDLを参照しテーブルを生成してください。
C:\Interstage\F3FMisjee\lib\install\databases
/opt/FJSVisjee/lib/install/databases
データベース | DDLファイル名 |
---|---|
Java DB | ejbtimer_derby.sql |
Oracle | ejbtimer_oracle.sql |
SQL Server | ejbtimer_mssqlserver.sql |
テーブルに格納するデータについて
以下に、タイマー用のテーブルにアクセスするタイミングについて説明します。
テーブルアクセスのタイミング | 目的 |
---|---|
タイマー登録時 | 当該タイマーのレコードを追加します。 |
コールバックメソッド実行直前 | 当該タイマーがキャンセルされていないかを確認します。 |
コールバックメソッド実行直後 | 当該タイマーのコールバックメソッド実行日時を更新します。 |
タイマーのgetInfoメソッドの初回実行時 | 当該タイマーの情報オブジェクトを読み込みます。 |
タイマーのcancelメソッド実行時 | 当該タイマーのレコードを削除します。 |
TimerServiceのgetTimersメソッド実行時 | サーバーインスタンスに登録されているタイマーのレコードを読み込みます。 |
サーバーインスタンス起動時 | 登録済みのタイマーを読み込みます。また、サーバーインスタンス停止状態で当該モジュールが再配備されている場合には、タイマーをすべて削除します。 |
モジュールの配備解除 (注) | 当該モジュールに関係するタイマーをすべて削除します。 |
モジュールの再配備 (注) | 当該モジュールに関係するタイマーをすべて削除します。 |
モジュールの非活性 (注) | 当該モジュールに関係するタイマーをすべて削除します。 |
注) サーバーインスタンス停止中状態の場合は、テーブルにアクセスしません。サーバーインスタンス起動中状態の場合だけテーブルにアクセスし、タイマーを削除します。
サーバーインスタンス起動時に、異常によりデータソースのアクセスに失敗した場合、サーバーログにISJEE_EJB5108警告メッセージが出力され、タイマーサービスが無効になります。その場合、EJBタイマーサービスが取得できません。
テーブルに不整合が発生した場合、または不要になったタイマーが残っている場合、DBMSのツールを使用して不要なタイマーの行を検索し削除してください。
以下に、テーブルに格納するデータについて説明します。
カラム名 | データの値 | データ内容の説明 |
---|---|---|
TIMERID | 文字列 | サーバーインスタンス名を含む内部IDです。 |
OWNERID | 文字列 | サーバーインスタンス名です。 |
CREATIONTIMERAW | ミリ秒 (注) | タイマーの生成日時です。 |
BLOB | バイナリ | タイマー生成時にcreateTimerメソッドの最終引数で渡す情報オブジェクトです。 |
CONTAINERID | 数値 | TimedObjectを実装するBeanの内部IDです。 |
STATE | 数値 | タイマーの状態です。
|
PKHASHCODE | 数値 | 内部コードです。 |
INTERVALDURATION | ミリ秒 | コールバック処理を繰り返し実行する場合の配信間隔です。 |
INITIALEXPIRATIONRAW | ミリ秒 (注) | 初回のコールバック処理実行の日時です。 |
LASTEXPIRATIONRAW | ミリ秒 (注) | 前回のコールバック処理実行の日時です。 |
注) 日時設定は、1970年1月1日 0:00:00からのミリ秒
タイマーサービスの設定について
配信間隔が短く指定されるとタイマー処理がサーバの負荷となるため、IJServerクラスタに対して配信間隔の最小値を指定できます。タイマーの生成時に指定された配信間隔がIJServerクラスタに定義した最小配信間隔より小さい場合に、最小配信間隔の値が使用されます。(注)
トランザクション内でロールバックされた場合、または例外が発生した場合、再配信間隔に指定された時間待機後にEJBタイマーサービスはコールバック処理を再実行します。これを、EJBタイマーサービスの再配信と呼びます。
再配信に失敗した場合には、繰り返し再配信します。しかし、最大再配信回数分の再配信を実行してもコールバック処理が成功しなかった場合、EJBタイマーサービスは再配信を終了して、該当のタイマーを削除します。
EJBタイマーサービスには、以下を指定できます。指定は、Interstage Java EE管理コンソール、またはasadminコマンドのget/setサブコマンドを使用して、IJServerクラスタ単位に設定できます。詳細は、Interstage Java EE管理コンソールのヘルプ、または「11.1 asadmin」を参照してください。
最小配信間隔
最大再配信回数
再配信間隔
タイマーデータソース
注)EJBタイマーの実行予定時刻は指定された日時や配信間隔からコンテナ内部で算出して決定します。膨大な値を指定された場合(例えばjava.lang.Long.MAX_VALUE値)、long値が桁あふれしてマイナス値となり、最小配信間隔より小さくなるため、最小配信間隔の値が使用される場合があります。
タイマーの正確性と処理遅延時の動作
負荷が集中するとタイマーの開始時間がずれる場合があります。
タイマーの処理がすぐに完了せず、後続のタイマーの実行時間が来た場合、後続のタイマーは実行中のタイマーの完了を待ちます。実行中のタイマーが完了後、実行予定時刻が超過しているタイマーは、ただちに実行されます。一定間隔で実行するタイマーの場合、実行予定時刻を越えている処理分連続して実行されます。
IJServerクラスタを複数プロセス構成で運用する場合の注意事項
生成したタイマーは、そのサーバーインスタンスで動作し、そのサーバーインスタンス上でEnterprise Beanインスタンスのタイマーコールバックメソッドを実行します。TimerServiceのgetTimersメソッドを実行すると、IJServerクラスタのすべてのサーバーインスタンスに存在するタイマーを取得できます。タイマーをキャンセルすると、データベースのテーブルから該当のレコードが削除されるため、IJServerクラスタの他サーバーインスタンスで動作するタイマーもキャンセルできます。ただし、タイマーの情報オブジェクトは、getInfoメソッドの初回実行時にテーブルから読み込まれるため、他サーバーインスタンスのタイマーを削除すると、タイマーが動作しているサーバーインスタンス上でgetInfoメソッドを実行した際に失敗する可能性があります。その場合、getInfoメソッドがjavax.ejb.NoSuchObjectLocalException例外をスローします。
タイマーを生成する時、EJBタイマーサービスがタイマーの情報と合わせてサーバーインスタンス名をデータベースに格納します。IJServerクラスタを再起動すると、IJServerクラスタの各サーバーインスタンスが同一のサーバーインスタンス名ですでに登録されているタイマーの情報をデータベースから取得します。そのため、IJServerクラスタのサーバーインスタンスを削減してIJServerクラスタを起動すると、登録されたタイマーが一部回復されない可能性があります。サーバーインスタンスを削減する場合、回復されないタイマーのレコードをデータベースから削除し、タイマーを再度登録してください。