私のpythonスクリプトは、別のデータソースからメッセージを受信すると、常にRabbitMQにメッセージを送信する必要があります。pythonスクリプトがメッセージを送信する頻度は、 、1分〜30分。
RabbitMQへの接続を確立する方法は次のとおりです。
rabt_conn = pika.BlockingConnection(pika.ConnectionParameters("some_Host"))
channel = rbt_conn.channel()
例外が発生しました
pika.exceptions.ConnectionClosed
どうすれば再接続できますか?最良の方法は何ですか? 「戦略」はありますか? pingを送信して接続を維持したり、タイムアウトを設定したりできますか?
どんなポインタでも大歓迎です。
RabbitMQはheartbeatsを使用して、「デッド」接続を検出して閉じ、ネットワークデバイス(ファイアウォールなど)が「アイドル」接続を終了しないようにします。バージョン3.5.5以降では、デフォルトのタイムアウトは60秒に設定されています(以前は〜10分でした)。 docs から:
ハートビートフレームは、約2秒ごとに送信されます。 2つのハートビートが失われた後、ピアは到達不能と見なされます。
PikaのBlockingConnectionの問題は、API呼び出しが行われるまでハートビートに応答できないことです(たとえば、channel.basic_publish()
、connection.sleep()
、等)。
これまでに見つけたアプローチ:
RabbitMQは、接続を確立するときにクライアントとタイムアウトをネゴシエートします。理論的には、_heartbeat_interval
_引数を使用してサーバーのデフォルト値をより大きな値で上書きすることは可能ですが、現在のPikaバージョン(0.10.0)はminサーバーとクライアントが提供する値の間の値。この問題は現在の master で修正されています。
一方、_heartbeat_interval
_引数を_0
_に設定することにより、ハートビート機能を完全に非アクティブ化することができます。これにより、新しい問題(ファイアウォールによる接続のドロップなど)が発生する可能性があります。
@itsafireの答えを拡張して、独自のpublisherクラスを記述して、必要に応じて再接続することができます。単純な実装の例:
_import logging
import json
import pika
class Publisher:
EXCHANGE='my_exchange'
TYPE='topic'
ROUTING_KEY = 'some_routing_key'
def __init__(self, Host, virtual_Host, username, password):
self._params = pika.connection.ConnectionParameters(
Host=host,
virtual_Host=virtual_Host,
credentials=pika.credentials.PlainCredentials(username, password))
self._conn = None
self._channel = None
def connect(self):
if not self._conn or self._conn.is_closed:
self._conn = pika.BlockingConnection(self._params)
self._channel = self._conn.channel()
self._channel.exchange_declare(exchange=self.EXCHANGE,
type=self.TYPE)
def _publish(self, msg):
self._channel.basic_publish(exchange=self.EXCHANGE,
routing_key=self.ROUTING_KEY,
body=json.dumps(msg).encode())
logging.debug('message sent: %s', msg)
def publish(self, msg):
"""Publish msg, reconnecting if necessary."""
try:
self._publish(msg)
except pika.exceptions.ConnectionClosed:
logging.debug('reconnecting to queue')
self.connect()
self._publish(msg)
def close(self):
if self._conn and self._conn.is_open:
logging.debug('closing queue connection')
self._conn.close()
_
まだ検討していなかった他の可能性:
connection.sleep()
を呼び出してサーバーのハートビートに応答します。非常にシンプル:このようなパターン。
import time
while True:
try:
communication_handles = connect_pika()
do_your_stuff(communication_handles)
except pika.exceptions.ConnectionClosed:
print 'oops. lost connection. trying to reconnect.'
# avoid rapid reconnection on longer RMQ server outage
time.sleep(0.5)
おそらく、コードをリファクタリングする必要がありますが、基本的には、例外をキャッチし、問題を軽減して作業を続行することです。 communication_handles
チャネル、キューなど、pikaを介してRabbitMQと通信するために必要なすべてのpika要素を含みます。