解决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操作RabbitMQ服务器实现消息队列的路由功能
Jun 29 Python
django实现前后台交互实例
Aug 07 Python
Django的HttpRequest和HttpResponse对象详解
Jan 26 Python
Python多线程中阻塞(join)与锁(Lock)使用误区解析
Apr 27 Python
Python设计模式之建造者模式实例详解
Jan 17 Python
新年快乐! python实现绚烂的烟花绽放效果
Jan 30 Python
python Tkinter版学生管理系统
Feb 20 Python
详解用Python练习画个美队盾牌
Mar 23 Python
Django Celery异步任务队列的实现
Jul 24 Python
python GUI库图形界面开发之PyQt5菜单栏控件QMenuBar的详细使用方法与实例
Feb 28 Python
vscode配置anaconda3的方法步骤
Aug 08 Python
Python基础之数据结构详解
Apr 28 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
set_include_path和get_include_path使用及注意事项
2013/02/02 PHP
PHP中if和or运行效率对比
2014/12/12 PHP
php使用ob_flush不能每隔一秒输出原理分析
2015/06/02 PHP
php技术实现加载字体并保存成图片
2015/07/27 PHP
PHP实现阿里大鱼短信验证的实例代码
2017/07/10 PHP
jquery获取复选框被选中的值
2014/03/22 Javascript
JS使用replace()方法和正则表达式进行字符串的搜索与替换实例
2014/04/10 Javascript
jquery实现个人中心导航菜单效果和美观都非常不错
2014/09/02 Javascript
鼠标悬浮停留三秒后自动显示大图js代码
2014/09/09 Javascript
基于html5和nodejs相结合实现websocket即使通讯
2015/11/19 NodeJs
vuex实现简易计数器
2016/10/27 Javascript
JavaScript原生数组Array常用方法
2017/04/06 Javascript
JS组件系列之JS组件封装过程详解
2017/04/28 Javascript
react-native 完整实现登录功能的示例代码
2017/09/11 Javascript
Vue移动端用淘宝弹性布局lib-flexible插件做适配的方法
2020/05/26 Javascript
jQuery+css实现的点击图片放大缩小预览功能示例【图片预览 查看大图】
2020/05/29 jQuery
JS性能优化实现方法及优点进行
2020/08/30 Javascript
npm ci命令的基本使用方法
2020/09/20 Javascript
[03:30]完美盛典趣味短片 CSGO2019年度名场面
2019/12/07 DOTA
[01:54]TI珍贵瞬间系列(三):翻盘
2020/08/28 DOTA
Python实现一个转存纯真IP数据库的脚本分享
2017/05/21 Python
Python面向对象编程之继承与多态详解
2018/01/16 Python
python检索特定内容的文本文件实例
2018/06/05 Python
pandas进行数据的交集与并集方式的数据合并方法
2018/06/27 Python
django+mysql的使用示例
2018/11/23 Python
面向中国市场的在线海淘美妆零售网站:Beauty House美丽屋
2021/03/02 全球购物
sealed修饰符是干什么的
2012/10/23 面试题
大专生简历的自我评价
2013/11/26 职场文书
幼儿园个人师德总结
2015/02/06 职场文书
幼儿园秋季开学通知
2015/07/16 职场文书
小学生优秀作文范文(六篇)
2019/07/10 职场文书
销区经理年终述职报告模板
2019/11/28 职场文书
pytorch中的torch.nn.Conv2d()函数图文详解
2022/02/28 Python
利用uni-app生成微信小程序的踩坑记录
2022/04/05 Javascript
python库Tsmoothie模块数据平滑化异常点抓取
2022/06/10 Python
mysql幻读详解实例以及解决办法
2022/06/16 MySQL