解决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网络编程实例简析
Sep 26 Python
python检测远程服务器tcp端口的方法
Mar 14 Python
Python中join和split用法实例
Apr 14 Python
python通过自定义isnumber函数判断字符串是否为数字的方法
Apr 23 Python
基于wxpython实现的windows GUI程序实例
May 30 Python
Sanic框架流式传输操作示例
Jul 18 Python
介绍一款python类型检查工具pyright(推荐)
Jul 03 Python
Python-copy()与deepcopy()区别详解
Jul 12 Python
Python csv模块使用方法代码实例
Aug 29 Python
Python实现淘宝秒杀功能的示例代码
Jan 19 Python
Python中Selenium对Cookie的操作方法
Jul 09 Python
Python实现Matplotlib,Seaborn动态数据图
May 06 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 smarty模版引擎中的缓存应用
2009/12/11 PHP
php实现单链表的实例代码
2013/03/22 PHP
php采集文章中的图片获取替换到本地(实现代码)
2013/07/08 PHP
百度实时推送api接口应用示例
2014/10/21 PHP
ioncube_loader_win_5.2.dll的错误解决方法
2015/01/04 PHP
php微信支付之APP支付方法
2015/03/04 PHP
PHP实现的登录,注册及密码修改功能分析
2016/11/25 PHP
老生常谈PHP中的数据结构:DS扩展
2017/07/17 PHP
TFDN图片播放器 不错自动播放
2006/10/03 Javascript
javascript一些不错的函数脚本代码
2008/09/10 Javascript
JavaScript 格式字符串的应用
2010/03/29 Javascript
jQuery下扩展插件和拓展函数的写法(匿名函数使用的典型例子)
2010/10/20 Javascript
基于jquery的返回顶部效果(兼容IE6)
2011/01/17 Javascript
js 字符串转化成数字的代码
2011/06/29 Javascript
JS中的hasOwnProperty()、propertyIsEnumerable()和isPrototypeOf()
2016/08/11 Javascript
基于vue实现swipe分页组件实例
2017/05/25 Javascript
webpack热模块替换(HMR)/热更新的方法
2018/04/05 Javascript
node使用Mongoose类库实现简单的增删改查
2018/11/08 Javascript
jquery实现简单自动轮播图效果
2020/07/29 jQuery
原生js实现自定义滚动条组件
2021/01/20 Javascript
python教程之用py2exe将PY文件转成EXE文件
2014/06/12 Python
python图像处理之镜像实现方法
2015/05/30 Python
利用pandas进行大文件计数处理的方法
2018/07/25 Python
Python里字典的基本用法(包括嵌套字典)
2019/02/27 Python
Python模拟键盘输入自动登录TGP
2020/11/27 Python
python 将Excel转Word的示例
2021/03/02 Python
浅谈CSS3 box-sizing 属性 有趣的盒模型
2019/04/02 HTML / CSS
HTML5实现无刷新修改URL的方法
2019/11/14 HTML / CSS
嘻哈珠宝品牌:KRKC&CO
2020/10/19 全球购物
社会实践活动总结报告
2014/04/29 职场文书
护士节演讲稿开场白
2014/08/25 职场文书
2014年社区妇联工作总结
2014/12/02 职场文书
我们的节日端午节活动总结
2015/02/11 职场文书
2015年社区党务工作总结
2015/04/21 职场文书
庭外和解协议书
2016/03/23 职场文书
Python获取指定日期是"星期几"的6种方法
2022/03/13 Python