MSMQでRubyからメッセージ受送信できる方法を調べてみたのでメモ。
ちょっと調べてみたところ、RubyにはMSMQ向けのライブラリはないようなのでWIN32OLE経由で呼び出だすことにします。よって、ホストがWindowsでない場合、以下のサンプルスクリプトは動作しません。MSMQのCOMのインタフェイスについてはMSDNの「メッセージ キュー COM コンポーネント」で調べることができます。
プログラミング自体はそんなに難しくはありませんが、ハマりやすいポイントとしてはキューがトランザクションキューかそうでないかで、受送信方法が異なることでしょうか。トランザクションキューにするか否かの設定はキュー作成時に行う必要があり、作成後は変更することができないので、うっかりキューの種類にそぐわない方法で受送信を行おうとするとうまくいきません。
† 非トランザクションキューの受送信
msmq_nontr_get.rbの方は永久ループでメッセージを取得するようになっているので、msmq_nontr_get.rbを起動させてから、msmq_nontr_put.rbを起動するとメッセージが1つずつ取得される様子を見ることができます。
msmq_nontr_put.rb
#!ruby -Ks
require 'win32ole'
module MSMQ; end
WIN32OLE::const_load(WIN32OLE.new('MSMQ.MSMQQueueInfo'), MSMQ)
QUEUE_NAME = 'test'
dest = WIN32OLE.new('MSMQ.MSMQDestination')
dest.PathName = '.\private$\\' + QUEUE_NAME
msg = WIN32OLE.new('MSMQ.MSMQMessage')
msg.Label = "FooLabel"
msg.Body = "BarBody"
msg.Priority = 1
# Put message into non-transactional queue
msg.Send(dest)
msmq_nontr_get.rb
#!ruby -Ks
require 'win32ole'
module MSMQ; end
WIN32OLE::const_load(WIN32OLE.new('MSMQ.MSMQQueueInfo'), MSMQ)
QUEUE_NAME = 'test'
# Get message from non-transactional queue
mqi = WIN32OLE.new('MSMQ.MSMQQueueInfo')
mqi.PathName = '.\private$\\' + QUEUE_NAME
q = mqi.Open(MSMQ::MQ_RECEIVE_ACCESS,MSMQ::MQ_DENY_NONE)
while true
msg = q.Receive
puts "Recieved!: Label:#{msg.Label}, Body:#{msg.Body}, Priority:#{msg.Priority}"
end
† トランザクションキューの受送信
こちらはキューがトランザクションをサポートする場合です。「づめメモ MSMQのトランザクション機能を試すRubyスクリプト」を参考にさせていただきました。こちらも上記と同様に、msmq_tr_get.rbを起動させてからmsmq_tr_put.rbを起動することで1つずつ処理がされていく様子を見ることができます。
msmq_tr_put.rb
#!ruby -Ks
require 'win32ole'
module MSMQ; end
WIN32OLE::const_load(WIN32OLE.new('MSMQ.MSMQQueueInfo'), MSMQ)
QUEUE_NAME = 'test_tr'
dest = WIN32OLE.new('MSMQ.MSMQDestination')
dest.PathName = '.\private$\\' + QUEUE_NAME
msg = WIN32OLE.new('MSMQ.MSMQMessage')
msg.Label = "FooLabel"
msg.Body = "BarBody"
msg.Priority = 1
# Put message into transactional queue ( w/o MSMQTransaction )
msg.Send("DestinationQueue"=> dest,"Transaction"=>MSMQ::MQ_SINGLE_MESSAGE)
# Put message into transactional queue ( w/ MSMQTransaction )
trd = WIN32OLE.new("msmq.MSMQTransactionDispenser")
tr = trd.begintransaction
msg.Send("DestinationQueue"=> dest,"Transaction"=>tr)
tr.commit
msmq_tr_get.rb
#!ruby -Ks
require 'win32ole'
module MSMQ; end
WIN32OLE::const_load(WIN32OLE.new('MSMQ.MSMQQueueInfo'), MSMQ)
QUEUE_NAME = 'test_tr'
# Get message from transactional queue ( w/ MSMQTransaction )
mqi = WIN32OLE.new('MSMQ.MSMQQueueInfo')
mqi.PathName = '.\private$\\' + QUEUE_NAME
q = mqi.Open(MSMQ::MQ_RECEIVE_ACCESS,MSMQ::MQ_DENY_NONE)
trd = WIN32OLE.new("msmq.MSMQTransactionDispenser")
while true
tr = trd.begintransaction
msg = q.Receive("Transaction"=>tr)
puts "Recieved!: Label:#{msg.Label}, Body:#{msg.Body}, Priority:#{msg.Priority}"
tr.commit
end