S2JMS 開発記 ExecutionContext と TransactionManager
WorkManager
の簡単な実装が概ね終了.
「簡単な実装」というのはスレッドプールをきめ細かく制御とかしていないため.例えばスレッドのプライオリティとか,スレッドプールにリクエストするキューの最大長を設定したりプライオリティキューにしたりなどなど.
大がかりなアプリケーションサーバならこの辺もちゃんとしないといけないのかもしれませんが,スタンドアロンな S2JMS-Container での利用を前提にするならあまり必要な状況にはならないような気のせいが.
そんなわけで (どんなわけで?),概ね終了.
「概ね終了」ということはまだ終了には至っていないわけですが,その大きなものが javax.resource.spi.work.ExecutionContext
のサポート.これがやっかいなんですよ.
ExecutionContext
というのは,リソースアダプタが受信したメッセージをワーカスレッド上で実行する際のトランザクションコンテキストを指定するもので,以下の二つのプロパティがあります.
- transactionTimeout
- xid
前者はまぁどうでもいいとして (いいのか?),問題は後者の xid.もちろん javax.transaction.xa.Xid
です.
昨日も書いたように,JCA + JMS + MDB というか要するに J2EE 改め JavaEE なプラットフォームでは,JMS メッセージを受信するスレッドとそれを処理する MDB を実行するスレッドが異なるモデルを想定している模様.
これはちょうど,ネットワークサービスを提供するサーバアプリケーションなどで,listen()〜accept()
するスレッドと,接続したコネクションからデータを受信して処理するスレッドを別にするのと同じようなものかな,と思います.
が,しかし.
JMS では接続待ちの代わりにメッセージの受信を行うわけですが,トランザクショナルにメッセージングを行う場合,その受信もトランザクションの一部になるという点に注意が必要.
んで,ですね.
JCA + JMS + MDB ではワーカスレッドで MDB の MessageListener#onMessage(Message)
を呼び出すわけですが,トランザクション境界はこの周囲に設定することになるっぽい.
つまり,ワーカスレッドで
TransactionManager#begin()
MessageListener#onMessage(Message)
TransactionManager#commit()
ってことになるみたいなんですが (これを実際に行うのが先に書いた MessageEndpoint
),これより前,ワーカスレッドに処理が届く前に JMS 実装はメッセージを受信しちゃってるわけで,それをどうやってこのトランザクションの一部にしたらよかとですか?
そんなわけで (どんなわけで?),ExecutionContext
です.
通常の JTA トランザクション制御では,リソースマネージャはトランザクションマネージャから渡された Xid
を使うのですが,JCA の Message Inflow なシナリオではリソースマネージャはトランザクションマネージャと関わることなく自分で勝手に Xid
を割り当ててトランザクションを開始してメッセージを受信しちゃう模様.
んで,その Xid
を ExecutionContext
に詰め込んでアプリケーションサーバに渡します.
そしてアプリケーションサーバはリソースマネージャが割り当てた Xid
をトランザクションマネージャに「インポート」するみたいなんですねぇ.
といっても,JTA 仕様では TransactionManager
あるいは Transaction
にそんなインタフェースは用意されていないので,トランザクションマネージャ固有のやり方で実装しろってことみたい.うーみゅ...
当然,現在の S2JTA ではそんな機能を持っていないので,手を加えないといけない感じ.
たぶん,TransactionManagerImpl
に begin(Xid, XAResource)
みたいなメソッドを追加するのかなぁ.
この XAResource
はもちろんメッセージを受信したリソースアダプタなのですが,そいつの start(Xid, int)
を呼び出すべきかどうかはまだ不明.どこに書いてあるの?
可能性としては,
- リソースは開始されていない.
TMNOFLAGS
でstart(Xid, int)
を呼び出す. - リソースはサスペンドしている.
TMRESUME
でstart(Xid, int)
を呼び出す. - リソースは開始されている.
prepare(Xid)
等を呼び出すまでやることなし.
といった辺りかなぁ.
最悪 JBoss や Geronimo のコードを追っかけて同じような振る舞いにするしかないかも〜.あ,ActiveMQ のリソースアダプタをチェックした方がいいかも.
そんなわけで (どんなわけで?),ちょっと時間がかかりそうですが,どっちみちこの辺の制御は WorkManager
ではなく MessageEndpoin
で対応することになりそうなので,WorkManager
としては一区切りかな.
ともあれ (JW),最新の S2JMS&S2JCA を明日 (01/04) 中に seasar.org の SVN に突っ込みたいと思います.
某巨大掲示板
ぐはぁっ,またこっちに風向きが変わってる...
まぁ,年末年始は平穏だったからいいか.
それにしても 53 さん,あなたおもしろすぎます.超うけたよ.(^^;
そんなわけで (どんなわけで?),記念こぴぺ
53 名前:デフォルトの名無しさん[sage] 投稿日:2006/01/03(火) 20:34:30
日本国内的にはもちろん、おそらく東京でもシェアにおいては伊東美咲の圧勝。
東京近辺の技術的な集まりあるいは技術系ブログに蛯原友里のファンが出没するので
「日本国内では蛯原友里が優勢」のような錯覚をそこに居合わせた技術者(or 東京滞在中の
技術者)が抱くのかもしれない。
おたくへのアプローチについては電車男への出演等を行わなかった"空白の三ヶ月"
を巻き返すのは至難の業、その間に伊東美咲があきばで着実にシェアを伸ばしてしまった。
「その透明感は大人気ない」だけで伊東美咲での優勢を覆すのはおそらく無理。
あなたのblog以外で蛯原友里関連の書き込みが少ないのもマイナス要因
かもしれない。
#あなたが、他のモデルの写真を貼り付けているのををみたことはありませんね。逆にあなたに
#問いたい、何故いつも蛯原友里なのですか?答えなくて結構です。
#あなたの煽り文句(やっぱり CanCam 買うしか!!)を見ていると
#ユーザをCanCamに意図的に誘導しようとしている"印象を受けます。
#[蛇足 : 2005/12/29 14:00]
#http://d.hatena.ne.jp/koichik/20051228#1135792832の書き込みで
#Rayの陸守絵麻ちゃんを取り上げていますね。
#これで"やっぱり CanCam 買うしか!!"と書かれてもあまり説得力が...。
なんていうか,説得力があるような気のせいがしてしまいました (苦笑).
はい,確かに私は多くの人を CanCam に意図的に誘導していました.心より恥じる.
確かに説得力はないかも.無念だ.
でも大丈夫です.今年のエビちゃんはきっとみーたんの領域まで飛躍します.間違いない.
そんなわけで (どんなわけで?),やっぱり CanCam 買うしか!!
S2JMS 開発記 S2JMS-Container
S2JMS-Container をこもりさんにお願いするべく,簡単なイメージを書いておくテスト.
まずは基本的な位置づけを.
JMS と JCA を含めた J2EE アーキテクチャでは,非同期メッセージの受信はリソースアダプタが行います.
リソースアダプタは通常 JMS プロバイダが提供します.ActiveMQ だと lib/optional
の下にある activemq-ra-v.r.z.rar
がそれです.
リソースアダプタはメッセージを受信するとアプリケーションサーバに渡します.そのための「端点」を表すのが javax.resource.spi.endpoint.MessageEndpoing
です.
アプリケーションサーバは MessageEndpoint
の実装クラスでトランザクション制御など諸々のシステム的なサービスを付加します.
そして MessageEndpoint
はアプリケーションを呼び出します.
JMS の場合はアプリケーションは javax.jms.MessageListener
を実装します.
そんなわけで (どんなわけで?),
- リソースアダプタ →
MessageEndpoint
→MessageListener
という流れが見えてきます.
んで,この MessageEndpoint
は S2JCA で実装します.
そして MessageListener
を実装するのが S2JMS-Container になります.
S2JMS-Container は MessageEndpoint
から受け取った javax.jms.Message
を本当のアプリケーションコンポーネントにバインディングして,本当のリスナーメソッドを呼び出します.
中核の機能はこれだけ.たぶん.
まずは簡単な実装から始めるとすると,メッセージをバインディングするコンポーネントとリスナーメソッドを持つコンポーネントは同じだとして,
<component class="org.seasar.jms.container.JmsContainerImpl"> <property name="componentName">hogeAction</componentName> </component>
みたいにコンポーネントのキーをプロパティで受け取って,MessageListener#onMessage(Message)
が呼び出されたらその都度 S2 コンテナからコンポーネント (たぶん instance="request"
) を取得して,アノテーションの付けられたプロパティに受信したメッセージのヘッダやプロパティ,ボディを設定し,同じくアノテーションで示されたリスナーメソッドを呼び出します.
S2JMS-Container は Web コンテナの外で動くので,そのままだと instance="request"
なスコープは使えません.
そこで,独自の HttpServletRequest
の実装を用意します.
最初は S2 に含まれているモックでもいいかも.いずれは HttpServletRequest
の getHeader(String)
で Message
のヘッダ (もしかしたらプロパティ) にアクセスできたら便利かも.
あ,受信した Message
自身も request
スコープのコンポーネントとして登録して欲しいです.
最悪 Message
を参照しないとできないケースはあると思うので.
他にも Message#getJMSReplyTo()
の宛先に返信メッセージを送信したりとか.
といった感じです.
他にもアプリに便利なこととか思いついたらどんどん追加しちゃってください.
先の話としては,アプリケーションの処理が失敗 (例外がスローされた) した場合に更新した DB はロールバックするけど,メッセージは受信したことにする (つまり破棄する) 機能をサポートしたいと考えています.
ただしこれ,悩ましい課題が多いので,基本的なところができてからでいいかな,と.たぶん MethodInterceptor
で実装できると思うので.
そんなわけで (どんなわけで?),よろしくお願いします.