解决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实现远程调用MetaSploit的方法
Aug 22 Python
跟老齐学Python之永远强大的函数
Sep 14 Python
在Python中测试访问同一数据的竞争条件的方法
Apr 23 Python
在Python的struct模块中进行数据格式转换的方法
Jun 17 Python
Python三级菜单的实例
Sep 13 Python
python 3.7.0 安装配置方法图文教程
Aug 27 Python
python傅里叶变换FFT绘制频谱图
Jul 19 Python
python多线程扫描端口(线程池)
Sep 04 Python
Python Dataframe常见索引方式详解
May 27 Python
pandas to_excel 添加颜色操作
Jul 14 Python
python+selenium实现12306模拟登录的步骤
Jan 21 Python
聊聊pytorch测试的时候为何要加上model.eval()
May 23 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
Yii操作数据库的3种方法
2014/03/11 PHP
php常用文件操作函数汇总
2014/11/22 PHP
php中关于长度计算容易混淆的问题分析
2016/05/27 PHP
ThinkPHP框架实现的微信支付接口开发完整示例
2019/04/10 PHP
[原创]后缀就扩展名为js的文件是什么文件
2007/12/06 Javascript
ASP.NET jQuery 实例11 通过使用jQuery validation插件简单实现用户登录页面验证功能
2012/02/03 Javascript
JavaScript动态插入script的基本思路及实现函数
2013/11/11 Javascript
完美兼容IE,chrome,ff的设为首页、加入收藏及保存到桌面js代码
2014/12/17 Javascript
javascript模拟php函数in_array
2015/04/27 Javascript
深入解析Javascript闭包的功能及实现方法
2016/07/10 Javascript
BootStrap tab选项卡使用小结
2020/08/09 Javascript
jQuery基于xml格式数据实现模糊查询及分页功能的方法
2016/12/25 Javascript
jQuery动态生成不规则表格(前后端)
2017/02/21 Javascript
详解Vue 动态添加模板的几种方法
2017/04/25 Javascript
webpack学习笔记之代码分割和按需加载的实例详解
2017/07/20 Javascript
浅谈vue的iview列表table render函数设置DOM属性值的方法
2017/09/30 Javascript
详解js正则表达式验证时间格式xxxx-xx-xx形式
2018/02/09 Javascript
Vue数据双向绑定原理及简单实现方法
2018/05/18 Javascript
在博客园博文中添加自定义右键菜单的方法详解
2020/02/05 Javascript
[36:05]DOTA2亚洲邀请赛 3.31 小组赛 A组 Liquid vs Optic
2018/04/01 DOTA
Python中列表和元组的相关语句和方法讲解
2015/08/20 Python
Python实现将一个大文件按段落分隔为多个小文件的简单操作方法
2017/04/17 Python
Python标准库之collections包的使用教程
2017/04/27 Python
关于反爬虫的一些简单总结
2017/12/13 Python
python实现word 2007文档转换为pdf文件
2018/03/15 Python
python-pyinstaller、打包后获取路径的实例
2019/06/10 Python
python async with和async for的使用
2019/06/20 Python
使用Windows批处理和WMI设置Python的环境变量方法
2019/08/14 Python
python字符串,元组,列表,字典互转代码实例详解
2020/02/14 Python
Numpy一维线性插值函数的用法
2020/04/22 Python
css3 响应式媒体查询的示例代码
2019/09/25 HTML / CSS
html5 css3实例教程 一款html5和css3实现的小机器人走路动画
2014/10/20 HTML / CSS
产品质量保证书
2014/04/29 职场文书
奥巴马上海演讲稿
2014/09/10 职场文书
员工工作表扬信
2015/05/05 职场文书
荒岛余生观后感
2015/06/09 职场文书