ページの先頭行へ戻る
Interstage Application Server/Interstage Web Server Express Java EE運用ガイド(Java EE 6編)
FUJITSU Software

2.10.3 EJBタイマーサービス

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クラスタプロセスが再起動されると、タイマーが自動的に回復します。

タイマーの永続化について

タイマーを使用する場合、永続化のためのデータベースが必要です。使用するデータベースを用意してください。
タイマーをトランザクション内で生成すると、トランザクションの終了時にトランザクションのステータスに従って、タイマー情報の登録もコミットまたはロールバックされます。そのため、タイマーを使用するトランザクション内で別のJDBCデータソースやJMSリソースをアクセスする場合、グローバルトランザクションに対応するデータソース(XADataSource)を使用する必要があります。
グローバルトランザクションを使用すると性能のオーバーヘッドがあるため、タイマー生成処理やコールバック処理でJDBCのAPIまたはJPAを使用してデータベースにアクセスする場合には、タイマー永続化にも同じデータソースを使用することを推奨します。

以下の表にデータベースに用意するテーブルを示します。テーブル名は、「EJB__TIMER__TBL」にしてください。

カラム名

データ型のJDBCタイプ

データの長さ(最大値)

制約

TIMERID

VARCHAR

46 + [サーバーインスタンス名の長さ] + [IJServerクラスタ名の長さ]

PRIMARY KEY

OWNERID

VARCHAR

[サーバーインスタンス名の長さ]

NULL

CREATIONTIMERAW

BIGINT

19桁(9223372036854775807)
(Symfowareでは18桁)

NOT NULL

BLOB

LONGVARBINARY

プライマリキーと情報オブジェクトのバイナリサイズによる

NULL

CONTAINERID

BIGINT

19桁(9223372036854775807)
(Symfowareでは18桁)

NOT NULL

STATE

INTEGER

1桁

NOT NULL

PKHASHCODE

INTEGER

10桁(2147483647)

NOT NULL

INTERVALDURATION

BIGINT

19桁(9223372036854775807)
(Symfowareでは18桁)

NOT NULL

INITIALEXPIRATIONRAW

BIGINT

19桁(9223372036854775807)
(Symfowareでは18桁)

NOT NULL

LASTEXPIRATIONRAW

BIGINT

19桁(9223372036854775807)
(Symfowareでは18桁)

NOT NULL

SCHEDULE

VARCHAR

@Sucheduleアノテーションに設定した引数による

NULL

APPLICATIONID

BIGINT

19桁(9223372036854775807)
(Symfowareでは18桁)

NOT NULL

JDBCタイプとDBMSのSQLデータ型のマッピングについては、JDBCドライバのマニュアルを参照してください。


タイマーサービスの永続化は、以下のデータベースをサポートします。
アプリケーション開発時やサンプル動作のためにJava DBデータベースも使用できますが、動作保証されません。

EJBタイマーサービス用のデフォルトデータソースと接続プールを使用することで、タイマー用のテーブルを用意したJava DBデータベースを以下に作成することができます。IJServerクラスタを起動する前に、このデータベースをasadminコマンドのstart-databaseサブコマンドにより起動してください。

C:\Interstage\F3FMisje6\glassfish\databases
/opt/FJSVisje6/glassfish/databases

上記データベースを利用する場合、デフォルトデータソース「jdbc/__TimerPool」をIJServerクラスタのタイマーデータソースに指定してください。また、デフォルトの接続プールは「__TimerPool」です。EJBタイマーサービスで利用するデータベースを変更する場合は、__TimerPoolの設定を変更するか、デフォルトデータソース「jdbc/__TimerPool」に関連付けるJDBC接続プールを変更してください。JDBC接続プールの設定変更については「4.14 データベースの環境設定」を参照してください。


データベースごとのテーブル生成のDDLファイルが、以下に格納されています。DDLを参照し、テーブルを生成してください。

C:\Interstage\F3FMisje6\glassfish\lib\install\databases
/opt/FJSVisje6/glassfish/lib/install/databases

データベース

DDLファイル名

Symfoware

ejbtimer_symfoware.sql

Oracle

ejbtimer_oracle.sql

SQL Server

ejbtimer_mssqlserver.sql

Java DB

ejbtimer_derby.sql

テーブルに格納するデータについて

以下に、タイマー用のテーブルにアクセスするタイミングについて説明します。

テーブルアクセスのタイミング

目的

タイマー登録時

当該タイマーのレコードを追加します。

コールバックメソッド実行直前

当該タイマーがキャンセルされていないかを確認します。

コールバックメソッド実行直後

当該タイマーのコールバックメソッド実行日時を更新します。

タイマーのgetInfoメソッドの初回実行時

当該タイマーの情報オブジェクトを読み込みます。

タイマーのcancelメソッド実行時

当該タイマーのレコードを削除します。

TimerServiceのgetTimersメソッド実行時

サーバーインスタンスに登録されているタイマーのレコードを読み込みます。

サーバーインスタンス起動時

登録済みのタイマーを読み込みます。

モジュールの配備解除 (注)

当該モジュールに関係するタイマーをすべて削除します。

モジュールの再配備 (注)

当該モジュールに関係するタイマーをすべて削除します。

モジュールの非活性 (注)

当該モジュールに関係するタイマーをすべて削除します。

注) サーバーインスタンス停止中状態の場合は、テーブルにアクセスしません。サーバーインスタンス起動中状態の場合だけテーブルにアクセスし、タイマーを削除します。


サーバーインスタンスサービス起動時に、異常によりデータソースのアクセスに失敗した場合、サーバーログにEJB5108警告メッセージが出力され、タイマーサービスが無効になります。その場合、EJBタイマーサービスが取得できません。

テーブルに不整合が発生した場合、または不要になったタイマーが残っている場合、DBMSのツールを使用して不要なタイマーの行を検索し削除してください。


以下に、テーブルに格納するデータについて説明します。

カラム名

データの値

データ内容の説明

TIMERID

文字列

サーバーインスタンスのインスタンス名を含む内部IDです。

OWNERID

文字列

サーバーインスタンス名です。

CREATIONTIMERAW

ミリ秒 (注)

タイマーの生成日時です。

BLOB

バイナリ

タイマー生成時にcreateTimerメソッドの最終引数で渡す情報オブジェクトです。

CONTAINERID

数値

TimedObjectを実装するBeanの内部IDです。

STATE

数値

タイマーの状態です。

  • 0 (起動状態)

  • 1 (キャンセル処理中)

PKHASHCODE

数値

内部コードです。

INTERVALDURATION

ミリ秒

コールバック処理を繰り返し実行する場合の配信間隔です。
繰り返し実行しない場合、0となります。

INITIALEXPIRATIONRAW

ミリ秒 (注)

初回のコールバック処理実行の日時です。

LASTEXPIRATIONRAW

ミリ秒 (注)

前回のコールバック処理実行の日時です。
まだ実行されていなかった場合、0となります。

SCHEDULE

文字列

@Scheduleアノテーションで利用する情報オブジェクトです。@ScheduleアノテーションについてはEJB規約を参照してください。

APPLICATIONID

数値

Beanの内部IDです。

注) 日時設定は、1970年1月1日 0:00:00からのミリ秒

タイマーサービスの設定について

配信間隔が短く指定されるとタイマー処理がサーバの負荷となるため、IJServerクラスタに対して配信間隔の最小値を指定できます。タイマーの生成時に指定された配信間隔がIJServerクラスタに定義した最小配信間隔より小さい場合に、最小配信間隔の値が使用されます。(注)

トランザクション内でロールバックされた場合、または例外が発生した場合、再配信間隔に指定された時間待機後にEJBタイマーサービスはコールバック処理を再実行します。これを、EJBタイマーサービスの再配信と呼びます。
再配信に失敗した場合には、繰り返し再配信します。しかし、最大再配信回数分の再配信を実行してもコールバック処理が成功しなかった場合、EJBタイマーサービスは再配信を終了して、該当のタイマーを削除します。

EJBタイマーサービスには、以下を指定できます。指定は、asadminコマンドのget/setサブコマンドを使用して、IJServerクラスタ単位に設定できます

EJBタイマーサービスのタイマーデータソースはasadminコマンドのget/setサブコマンドを使用して設定できます。詳細は、「9.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クラスタを起動すると、登録されたタイマーが一部回復されない可能性があります。サーバーインスタンスを削減する場合、回復されないタイマーのレコードをデータベースから削除し、タイマーを再度登録してください。