[開発] Spring JMS の AbstractMessageListenerContainer っていう奴

tag:
JMS Spring AbstractMessageListenerContainer AbstractPollingMessageListenerContainer DefaultMessageListenerContainer SimpleMessageListenerContainer sessionAcknowledgeMode acknowledge sessionTransacted JtaTransactionManager JmsTransactionManager TransactionAwareConnectionFactoryProxy


Java 1.0a(アルファ版)がダウンロードできるようになったのが1994年
対し、JMSのfirst releaseが2001年
その差たった7年
Javaはともかく、JMSが未だに現役なのが凄い

両者とも取り巻く登場人物の変化は大きい
一番はやはりSpring?になるのか?
そのSpringも決してJMSを無視して折らず、Spring JMSがある
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/jms.html


JMSのそもそも仕様で、
開発者部品の任意のタイミングでJMS Providerに接続して電文を受信する同期受信と
JMS Providerが電文を受信したタイミングで開発者部品が呼び出される非同期受信とあるが、
Springもまたその両方をサポートしている。
特に後者の非同期受信でスポットライトを浴びるのが以下のSpringのクラスたち
AbstractMessageListenerContainer - AMLC
├- AbstractPollingMessageListenerContainer - APMLC
│ └- DefaultMessageListenerContainer - DMLC
└- SimpleMessageListenerContainer - SMLC

こやつ等を使用した非同期電文受信からのDB更新を同一トランザクションで管理できるか
というテーマが繰り広げられる訳なのだが、

その前提ともなる大切な事がAMLC のJavadocにしれっと書いてるのでメモメモ
Class AbstractMessageListenerContainer
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jms/listener/AbstractMessageListenerContainer.html
・ JMS の MessageListener を使うでも Spring SessionAwareMessageListener を使うでも良し
・ 通常はJMS Connectionを1つだけ保持し、全てのlistenerがそれを使いまわす。=超標準的なJMSのlistener sessionの管理方法
・ 外部リソースと同一トランザクションにするなどXAを使用する時は新規にConnectionを設ける。プロセスの登録はサブクラス依存
NOTE:
- デフォルトの message listener container は、如何なる例外が発生しようとも、log だけ吐いて JMS Provider へ回さない。
  =非同期受信がrollbackされ、一度受信した電文がQueueに返ることは無い ★留意されたし★
- と言えども、その発生例外をハンドリングしたい場合は、setErrorHandler で任意の例外ハンドラを設定すること
  ただし、その例外ハンドラは ExceptionListener が呼ばれた後に呼ばれることにご注意あれ ★留意されたし★

非同期受信した電文をQueueからdeleteしても良いかをJMS Providerに伝える仕組みがacknowledgeなるもの
acknowledgeすると電文がQueueから消える訳だが、コイツがまた曲者。


AMLC が提供する acknowledge オプションは以下の4つ:
- 1. sessionAcknowledgeMode = AUTO_ACKNOWLEDGE (default)
- 2. sessionAcknowledgeMode = DUPS_OK_ACKNOWLEDGE
- 3. sessionAcknowledgeMode = CLIENT_ACKNOWLEDGE
- 4. sessionTransacted = true

各オプションの詳細:

-- 1. sessionAcknowledgeMode = AUTO_ACKNOWLEDGE (default)
DMLC の場合 >>
  非同期受信した電文をacknowledgeしてから、listenerが呼ばれる。 ★留意されたし★
  電文のロールバックは起こりえず、同一電文が他のlistenerに食われることもない=同一電文の再配信なし ★留意されたし★
SMLC の場合 >>
  listenerが呼んでから、非同期受信した電文をacknowledgeする。 ★留意されたし★
  どんな例外が発生しようが電文のロールバックはしない=同一電文の再配信なし(DMLCと同じ) ★留意されたし★
  ※ ただし、JVM異常時はロールバックする可能性あり

-- 2. sessionAcknowledgeMode = DUPS_OK_ACKNOWLEDGE
lazy message acknowledgmentをするだけで、後はAUTO_ACKNOWLEDGEの時に同じ

-- 3. sessionAcknowledgeMode = CLIENT_ACKNOWLEDGE
呼び出されたlistenerの処理が成功した場合にのみacknowledgeする。
例外発生時は「best effort」で非同期受信をロールバックする=同一電文の再配信あり

-- 4. sessionTransacted = true
呼び出されたlistenerの処理が成功した場合にのみacknowledgeする。
例外発生時は「必ず」で非同期受信をロールバックする=同一電文の再配信あり

そんなこんなで同一電文の重複配信(duplicate message processing problem)の可能性は拭えない
対処法は2つ
・listenerに重複判定するロジックを入れる。cf. JMSRedelivered flag
・XAトランで全処理をラップする。
※ XAトランはオーバーヘッドがかかる点に留意されたい


☆ 推奨手法
sessionTransacted = ture にしとくがよろし。
  特に listener からlocalのDBを更新する場合。
  ただし、重複配信の対策はロジックでよしなにやる必要あり。
・ もしくは、JtaTransactionManager をtransactionManagerに設定してXAトランにする。

☆ 注意
XAトランかJTAの場合にのみ、JmsTransactionManagerを使用し、
それ以外の場合は、sessionTransacted を使用するのが良い (JtaTransactionManagerは使わずに)。


所変わって、APMLC
AbstractPollingMessageListenerContainer#setTransactionManager
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jms/listener/AbstractPollingMessageListenerContainer.html#setTransactionManager-org.springframework.transaction.PlatformTransactionManager-
電文の受信とlistener処理をwrapするトランのマネージャを登録する。
デフォはnull
設定される場合は、基本 Spring の JtaTransactionManager かそのさぶクラス。JTA-aware ConnectionFactory とsetで使用するのが王道

NOTE:
JTA より local JMS transaction の使用を検討すべき。
local JMS transaction なら、単純にsessionTransactedをtrueにするだけで、非同期受信以降の SessionAwareMessageListenerで呼び出されるsessionを包括できる。
つまり、JmsTransactionManagerと同等のことをlocal JMS transactionで叶う。


で、そのJmsTransactionManagerとは何ぞや?
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jms/connection/JmsTransactionManager.html
・ 任意のConnectionFactoryからConnectionとsessionを取得してthreadに割り振るのが仕事。
・ local strategyで、JTA でのJMS実行の代替手段
・ Prosは、如何なる環境で作動すること。Standaloneでもtest suiteでもmessage brokerとの連携だって可能。
・ Consは、JMSトランとDBトランを1トランで扱うなどのJTA/XAトランの制御はできない。それやるなら、SpringのJtaTransactionManagerをstrategyとすべき。


## なんかもやっとする
## AUTO_ACKNOWLEDGEやDUPS_OK_ACKNOWLEDGEは良いけど、
## sessionTransacted=trueで基本的に有無言わさず非同期受信をcommit(acknowledge)するかどうか記述が曖昧
## sessionTransactedにする場合は、JVM死亡時以外は非同期受信電文のrollback無しな表現がまた曖昧
## plus, 仮にJVM死亡時以外は非同期受信電文のrollback無しの場合、他のacknowledge optionとの違いは何??


で、ググってたら新キャラ登場
TransactionAwareConnectionFactoryProxy - TACFP
ref.
Dr. David Syer, Distributed transactions in Spring, with and without XA - Seven transaction-processing patterns for Spring applications, JAN 6, 2009 12:00 AM PT
http://www.javaworld.com/article/2077963/open-source-tools/distributed-transactions-in-spring--with-and-without-xa.html
な、長い..

tag : JMS Spring AbstractMessageListenerContainer AbstractPollingMessageListenerContainer DefaultMessageListenerContainer SimpleMessageListenerContainer sessionAcknowledgeMode acknowledge sessionTransacted JtaTransactionManager

2017-06-05 20:02 : 開発 : コメント : 0 : トラックバック : 0 :
コメントの投稿
非公開コメント

« next  ホーム  prev »

search

ad



counter


tag cloud

category cloud