簡體   English   中英

消費者取消后,RabbitMQ pika異步消費者心跳問題

[英]RabbitMQ pika async consumer heartbeat issue after consumer cancellation

使用RabbitMQ和pika(python),我正在運行一個作業排隊系統,為節點(異步消費者)提供任務。 定義任務的每條消息只有在任務完成后才會被確認。

有時我需要在這些節點上執行更新,並且我已經創建了一個退出模式,其中節點等待其任務完成,然后正常退出。 然后我可以執行維護工作。

因此,在此退出模式下,節點不會從RabbitMQ獲取更多消息,我讓它在等待作業完成之前調用basic_cancel方法。

pika文檔中描述了此方法的這種效果:

This method cancels a consumer. This does not affect already
delivered messages, but it does mean the server will not send any more
messages for that consumer. The client may receive an arbitrary number
of messages in between sending the cancel method and receiving the
cancel-ok reply. It may also be sent from the server to the client in
the event of the consumer being unexpectedly cancelled (i.e. cancelled
for any reason other than the server receiving the corresponding
basic.cancel from the client). This allows clients to be notified of
the loss of consumers due to events such as queue deletion.

因此,如果您將“已傳遞的消息”視為已收到但尚未確認的消息,則退出模式允許等待的任務不應重新排隊,即使運行它的消費者節點將自己從排隊系統中取消。

我的async使用者類的stop函數的代碼(取自pika示例)與此類似:

  def stop(self):
    """Cleanly shutdown the connection to RabbitMQ by stopping the consumer
    with RabbitMQ. When RabbitMQ confirms the cancellation, on_cancelok
    will be invoked by pika, which will then closing the channel and
    connection. The IOLoop is started again because this method is invoked
    when CTRL-C is pressed raising a KeyboardInterrupt exception. This
    exception stops the IOLoop which needs to be running for pika to
    communicate with RabbitMQ. All of the commands issued prior to starting
    the IOLoop will be buffered but not processed.

    """
    LOGGER.info('Stopping')
    self._closing = True
    self.stop_consuming()
    LOGGER.info('Waiting for all running jobs to complete')
    for index, thread in enumerate(self.threads):
        if thread.is_alive():
           thread.join()
           # also tried with a while loop that waits 10s as long as the 
           # thread is still alive
           LOGGER.info('Thread {} has finished'.format(index))

    # also tried moving the call to stop consuming up to this point
    if self._connection!=None:
        self._connection.ioloop.start()
        LOGGER.info('Closing connection')
        self.close_connection()

我的問題是,在消費者取消后,異步消費者似乎不再發送心跳,即使我在等待我的任務(線程)完成的循環之后執行取消。

我已經閱讀了有關BlockingConnections的process_data_events函數,但我找不到這樣的函數。 SelectConnection類的ioloop是否等同於異步使用者?

由於我的退出模式節點不再發送心跳,一旦達到最大心跳,當前執行的任務將由RabbitMQ重新排隊。 我想保持這種心跳不受影響,因為當我不處於退出模式時,這不是問題(我的心跳大約是100秒,我的任務可能需要2個小時才能完成)。

看看RabbitMQ日志,心跳確實是原因:

=ERROR REPORT==== 12-Apr-2017::19:24:23 ===
closing AMQP connection (.....) :
missed heartbeats from client, timeout: 100s

我能想到的唯一解決方法是確認在退出模式下仍然運行的任務對應的消息,並希望這些任務不會失敗......

我可以使用通道或連接中的任何方法在等待時手動發送一些心跳嗎?

問題可能是time.sleep()或thread.join()方法(來自python線程包)充當阻塞並且不允許其他一些線程執行他們需要的東西嗎? 我在其他應用程序中使用它們似乎並不像這樣。

因為這個問題只出現在退出模式時,我想停止功能中有一些東西導致消費者停止發送心跳,但是我也試過(沒有任何成功)只在等待后調用stop_consuming方法-running-tasks循環,我看不出這個問題的根源是什么。

非常感謝你的幫助 !

結果是stop_consuming函數以異步方式調用basic_cancel並在channel.close()函數上進行回調,導致我的應用程序停止其RabbitMQ交互並且RabbitMQ重新排隊unackesdmessages。 實際上已經意識到,由於線程試圖稍后確認剩余的任務有錯誤,因為通道現在設置為None,因此不再有ack方法。

希望它可以幫到某人!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM