解决python3 pika之连接断开的问题


Posted in Python onDecember 18, 2018

问题描述

在消费rabbitMQ队列时, 每次进入回调函数内需要进行一些比较耗时的操作;操作完成后给rabbitMQ server发送ack信号以dequeue本条消息。

问题就发生在发送ack操作时, 程序提示链接已被断开或socket error。

源码示例

#!/usr/bin
#coding: utf-8

import pika
import time


USER = 'guest'
PWD = 'guest'
TEST_QUEUE = 'just4test'

def callback(ch, method, properties, body):
 print(body)
 time.sleep(600)
 ch.basic_publish('', routing_key=TEST_QUEUE, body="fortest")
 ch.basic_ack(delivery_tag = method.delivery_tag)

def test_main():
 s_conn = pika.BlockingConnection(
  pika.ConnectionParameters('127.0.0.1', 
   credentials=pika.PlainCredentials(USER, PWD)))
 chan = s_conn.channel()
 chan.queue_declare(queue=TEST_QUEUE)

 chan.basic_publish('', routing_key=TEST_QUEUE, body="fortest")
 chan.basic_consume(callback, queue=TEST_QUEUE)
 chan.start_consuming()

if __name__ == "__main__":
 test_main()

运行一段时间后, 就会报错:

[ERROR][pika.adapters.base_connection][2017-08-18 12:33:49]Error event 25, None
[CRITICAL][pika.adapters.base_connection][2017-08-18 12:33:49]Tried to handle an error where no error existed
[ERROR][pika.adapters.base_connection][2017-08-18 12:33:49]Fatal Socket Error: BrokenPipeError(32, 'Broken pipe')

问题排查

猜测:pika客户端没有及时发送心跳,连接被server断开

一开始修改了heartbeat_interval参数值, 示例如下:

def test_main():
 s_conn = pika.BlockingConnection(
  pika.ConnectionParameters('127.0.0.1', 
   heartbeat_interval=10,
   socket_timeout=5,
   credentials=pika.PlainCredentials(USER, PWD)))
 # ....

修改后运行依然报错,后来想想应该单线程被一直占用,pika无法发送心跳;

于是又加了个心跳线程, 示例如下:

#!/usr/bin
#coding: utf-8

import pika
import time
import logging
import threading

USER = 'guest'
PWD = 'guest'
TEST_QUEUE = 'just4test'

class Heartbeat(threading.Thread):
 def __init__(self, connection):
  super(Heartbeat, self).__init__()
  self.lock = threading.Lock()
  self.connection = connection
  self.quitflag = False
  self.stopflag = True
  self.setDaemon(True)

 def run(self):
  while not self.quitflag:
   time.sleep(10)
   self.lock.acquire()
   if self.stopflag :
    self.lock.release()
    continue
   try:
    self.connection.process_data_events()
   except Exception as ex:
    logging.warn("Error format: %s"%(str(ex)))
    self.lock.release()
    return
   self.lock.release()

 def startHeartbeat(self):
  self.lock.acquire()
  if self.quitflag==True:
   self.lock.release()
   return
  self.stopflag=False
  self.lock.release()

def callback(ch, method, properties, body):
 logging.info("recv_body:%s" % body)
 time.sleep(600)
 ch.basic_ack(delivery_tag = method.delivery_tag)

def test_main():
 s_conn = pika.BlockingConnection(
  pika.ConnectionParameters('127.0.0.1', 
   heartbeat_interval=10,
   socket_timeout=5,
   credentials=pika.PlainCredentials(USER, PWD)))
 chan = s_conn.channel()
 chan.queue_declare(queue=TEST_QUEUE)
 chan.basic_consume(callback,
      queue=TEST_QUEUE)

 heartbeat = Heartbeat(s_conn)
 heartbeat.start()   #开启心跳线程
 heartbeat.startHeartbeat()
 chan.start_consuming()

if __name__ == "__main__":
 test_main()

尝试运行,结果还是不行,不得不安静下来思考自己是不是想错了。

去看它的api,看到heartbeat_interval的解析:

:param int heartbeat_interval: How often to send heartbeats.
         Min between this value and server's proposal
         will be used. Use 0 to deactivate heartbeats
         and None to accept server's proposal.

按这样说法,应该还是没有把心跳值给设置好。上面的程序期望是10秒发一次心跳,但是理论上发送心跳的间隔会比10秒多一点。所以艾玛,我应该是把heartbeat_interval的作用搞错了, 它是指超过这个时间间隔不发心跳或不给server任何信息,server就会断开连接, 而不是说pika会按这个间隔来发心跳。 结果我把heartbeat_interval值设置高一点(比实际发送心跳/信息的间隔更长),比如上面设置成60秒,就正常运行了。

如果不指定heartbeat_interval, 它默认为None, 意味着按rabbitMQ server的配置来检测心跳是否正常。

如果设置heartbeat_interval=0, 意味着不检测心跳,server端将不会主动断开连接。

以上这篇解决python3 pika之连接断开的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
编写Python脚本把sqlAlchemy对象转换成dict的教程
May 29 Python
解决python文件字符串转列表时遇到空行的问题
Jul 09 Python
Python向MySQL批量插数据的实例讲解
Mar 31 Python
python spyder中读取txt为图片的方法
Apr 27 Python
django输出html内容的实例
May 27 Python
python人民币小写转大写辅助工具
Jun 20 Python
Python实现的对本地host127.0.0.1主机进行扫描端口功能示例
Feb 15 Python
Python分析彩票记录并预测中奖号码过程详解
Jul 09 Python
keras自定义损失函数并且模型加载的写法介绍
Jun 15 Python
matplotlib 画动态图以及plt.ion()和plt.ioff()的使用详解
Jan 05 Python
学点简单的Django之第一个Django程序的实现
Feb 24 Python
PO模式在selenium自动化测试框架的优势
Mar 20 Python
Python实现繁?转为简体的方法示例
Dec 18 #Python
python 自动重连wifi windows的方法
Dec 18 #Python
浅谈python中真正关闭socket的方法
Dec 18 #Python
对python中dict和json的区别详解
Dec 18 #Python
BP神经网络原理及Python实现代码
Dec 18 #Python
python 执行文件时额外参数获取的实例
Dec 18 #Python
python实现基于信息增益的决策树归纳
Dec 18 #Python
You might like
PHP中几个常用的魔术常量
2012/02/23 PHP
php操作XML、读取数据和写入数据的实现代码
2014/08/15 PHP
CI框架支持$_GET的两种实现方法
2016/05/18 PHP
全面解析PHP验证码的实现原理 附php验证码小案例
2016/08/17 PHP
Laravel中间件实现原理详解
2016/10/09 PHP
收集的网上用的ajax之chat.js文件
2007/04/08 Javascript
js模拟select下拉菜单控件的代码
2013/05/08 Javascript
JS阻止用户多次提交示例代码
2014/03/26 Javascript
js使用setTimeout实现定时炸弹的方法
2015/04/10 Javascript
jQuery常用的一些技巧汇总
2016/03/26 Javascript
jquery编写日期选择器
2017/03/16 Javascript
JavaScript ES6中const、let与var的对比详解
2017/06/18 Javascript
将angular.js项目整合到.net mvc中的方法详解
2017/06/29 Javascript
Vue的百度地图插件尝试使用
2017/09/06 Javascript
Bootstrap table中toolbar新增条件查询及refresh参数使用方法
2018/05/18 Javascript
让Vue也可以使用Redux的方法
2018/05/23 Javascript
Node.js爬虫如何获取天气和每日问候详解
2019/08/26 Javascript
基于layui table返回的值的多级嵌套的解决方法
2019/09/19 Javascript
[01:00:53]OG vs IG 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
[01:09:19]DOTA2-DPC中国联赛 正赛 VG vs Aster BO3 第二场 2月28日
2021/03/11 DOTA
python遍历 truple list dictionary的几种方法总结
2016/09/11 Python
对python .txt文件读取及数据处理方法总结
2018/04/23 Python
python selenium执行所有测试用例并生成报告的方法
2019/02/13 Python
50行Python代码获取高考志愿信息的实现方法
2019/07/23 Python
python itsdangerous模块的具体使用方法
2020/02/17 Python
python保留格式汇总各部门excel内容的实现思路
2020/06/01 Python
python用700行代码实现http客户端
2021/01/14 Python
The Beach People美国:澳洲海滨奢华品牌
2018/07/05 全球购物
大一军训感言
2014/01/09 职场文书
体育口号大全
2014/06/18 职场文书
财会专业毕业生自荐信
2014/07/09 职场文书
2014入党积极分子批评与自我批评思想汇报
2014/09/20 职场文书
事业单位个人总结
2015/02/12 职场文书
英文慰问信范文
2015/03/24 职场文书
创业计划书之少年玩具店
2019/09/05 职场文书
PHP对接阿里云虚拟号的实现(号码隐私保护)
2021/04/06 PHP