wait_for_notify
メソッドで適切な場所を探していますが、ActiveRecordはAPIを使用していないようですので、基礎となるPG :: Connectionオブジェクト(またはその1つ)を取得する必要がありますあなたがマルチスレッド設定を実行している場合)、ActiveRecordがPostgresと通信するために使用しています。
接続が完了したら、必要な文をLISTEN
文で実行し、ブロック(および任意のタイムアウト期間)をwait_for_notify
に渡します。これは現在のスレッドをブロックし、タイムアウトに達するか、NOTIFY
が発生するまでPostgresの接続を独占します(例えば、Webリクエストの中でこれをしたくない場合)。別のプロセスがあなたが聞いているチャネルの1つにNOTIFY
を発行すると、そのブロックは3つの引数、つまり通知されたチャネル、NOTIFY
を引き起こしたPostgresバックエンドのPID、およびNOTIFY
を伴うペイロード(もしあれば)。
私はかなりしばらくのActiveRecordを使用していないので、これを行うためのクリーンな方法があるかもしれませんが、これは4.0.0.beta1で無事に動作するようです:の例えば
# Be sure to check out a connection, so we stay thread-safe.
ActiveRecord::Base.connection_pool.with_connection do |connection|
# connection is the ActiveRecord::ConnectionAdapters::PostgreSQLAdapter object
conn = connection.instance_variable_get(:@connection)
# conn is the underlying PG::Connection object, and exposes #wait_for_notify
begin
conn.async_exec "LISTEN channel1"
conn.async_exec "LISTEN channel2"
# This will block until a NOTIFY is issued on one of these two channels.
conn.wait_for_notify do |channel, pid, payload|
puts "Received a NOTIFY on channel #{channel}"
puts "from PG backend #{pid}"
puts "saying #{payload}"
end
# Note that you'll need to call wait_for_notify again if you want to pick
# up further notifications. This time, bail out if we don't get a
# notification within half a second.
conn.wait_for_notify(0.5) do |channel, pid, payload|
puts "Received a second NOTIFY on channel #{channel}"
puts "from PG backend #{pid}"
puts "saying #{payload}"
end
ensure
# Don't want the connection to still be listening once we return
# it to the pool - could result in weird behavior for the next
# thread to check it out.
conn.async_exec "UNLISTEN *"
end
end
より一般的な使用方法については、Sequel's implementationを参照してください。
を追加して編集する:ここでは何が起こっているのかについての別の説明があります。これはバックグラウンドの背後にある正確な実装ではないかもしれませんが、動作を十分に説明しているようです。
Postgresは接続ごとに通知のリストを保持します。接続を使用してLISTEN channel_name
を実行すると、そのチャンネルの通知をこの接続のリストにプッシュする必要があります(複数の接続で同じチャンネルを聞くことができるので、1つの通知が多くのリストにプッシュされることがあります) 。同時に多数のチャネルに接続することができ、そのいずれかへの通知はすべて同じリストにプッシュされます。
wait_for_notify
は、接続のリストから最も古い通知をポップし、その情報をブロックに渡します。または、リストが空の場合は、通知が利用可能になるまでスリープし、同じことを(またはタイムアウトまで到達した場合、nilを返します)。 wait_for_notify
は1つの通知しか処理しないので、複数の通知を処理する場合は、繰り返し呼び出す必要があります。あなたUNLISTEN channel_name
またはUNLISTEN *
、Postgresが使用している接続のリストにそれらの通知をプッシュ停止しますが、すでにそのリストにプッシュされているものがそこに滞在し、それが次に呼び出されたときwait_for_notifyはまだそれらを返します
。これにより、wait_for_notify
の後に、しかしUNLISTEN
の前に蓄積された通知が、別のスレッドがその接続をチェックアウトしたときに引き続き存在する問題が発生する可能性があります。その場合、UNLISTEN
の後に、短いタイムアウトでnilを返すまでwait_for_notify
を呼び出すとよいでしょう。しかし、多くの異なる目的のためにLISTEN
とNOTIFY
を頻繁に使用していない限り、おそらくそれは心配する価値はありません。
上記のSequelの実装に対するより良いリンクを追加しました。私はそれを見ることをお勧めします。それはかなり簡単です。
私が正しく理解すれば、DBが情報をレールにプッシュするようにします。レールに何らかのリスナーがあれば、plperlを使ってこのリスナーに接続し、情報を配信することができます。 –
私は、そのリスナーとして動作するようにレールを設定する方法のサンプルコードを見つけようとしています。私はPostgresのLISTEN/NOTIFY能力のためにplperlが必要ではないと思っていますが、私はあなたが考えることができるものを試そうとしています –
私は心にハックを持っていました。 http://sequel.rubyforge.org/rdoc/files/doc/postgresql_rdoc.htmlまたはhttps://github.com/taotetek/listen_notify_poller/blob/master/example.rb –