Pika 1.0.0 BlockingConnection内部异常未转pika.exceptions及异常枚举咨询
1. Pika是否应将内部异常转换为pika.exceptions中的异常对外抛出?
在Pika 1.0.0版本中,确实存在像pika.adapters.utils.connection_workflow.AMQPConnectorStackTimeout这类内部模块异常没有被统一封装到pika.exceptions命名空间的情况。这并非设计上的有意为之,更多是连接工作流模块作为内部实现细节,其异常没有被上层代码统一转换为对外暴露的标准异常类型。
从用户友好性和API一致性角度来说,理想情况下Pika应该将所有对外抛出的异常统一到pika.exceptions下,这样开发者无需导入内部模块的异常即可处理所有情况。不过在1.0.0这个特定版本中,这是需要接受的现状——部分连接相关的异常会从内部模块直接抛出。
2. 如何枚举Pika可能抛出的所有异常,区分可重试临时异常和不可恢复异常?
要全面处理Pika的异常,你需要覆盖标准pika.exceptions异常和内部模块抛出的连接相关异常,并根据异常类型判断是否可重试:
第一步:列出需要捕获的核心异常类型
标准
pika.exceptions中的可重试异常:pika.exceptions.ConnectionClosed:连接被关闭,通常可重试pika.exceptions.ConnectionWrongStateError:连接状态错误,临时情况可重试pika.exceptions.ChannelClosed:通道关闭,若因连接问题导致可重试pika.exceptions.AMQPConnectionError:通用AMQP连接错误,多数情况可重试pika.exceptions.AMQPHeartbeatTimeout:心跳超时,网络波动导致,可重试
内部模块的可重试异常(针对1.0.0):
pika.adapters.utils.connection_workflow.AMQPConnectorStackTimeout:握手超时,网络延迟导致,可重试pika.adapters.utils.connection_workflow.AMQPConnectorAMQPHandshakeError:握手错误,临时网络问题可重试pika.adapters.utils.connection_workflow.AMQPConnectionWorkflowFailed:连接工作流失败,多数是临时问题可重试
不可恢复的异常:
pika.exceptions.InvalidCredentials:凭证错误,需修改配置,不可重试pika.exceptions.ProtocolSyntaxError:AMQP协议语法错误,通常是参数配置错误,不可重试pika.exceptions.UnsupportedAMQPFieldException:不支持的AMQP字段,配置问题,不可重试pika.exceptions.ChannelWrongStateError:通道状态错误(如已关闭后操作),逻辑错误,不可重试
第二步:实现异常捕获与重试逻辑示例
你可以通过分层捕获异常,先处理标准异常,再处理内部模块的异常,示例代码如下:
import pika from pika.adapters.utils.connection_workflow import ( AMQPConnectorStackTimeout, AMQPConnectorAMQPHandshakeError, AMQPConnectionWorkflowFailed ) import time def create_connection_with_retry(parameters, max_retries=5, retry_delay=3): retries = 0 while retries < max_retries: try: return pika.BlockingConnection(parameters) except (pika.exceptions.AMQPConnectionError, pika.exceptions.ConnectionClosed, pika.exceptions.AMQPHeartbeatTimeout, AMQPConnectorStackTimeout, AMQPConnectorAMQPHandshakeError, AMQPConnectionWorkflowFailed) as e: retries += 1 print(f"Connection failed (retry {retries}/{max_retries}): {str(e)}") time.sleep(retry_delay) except (pika.exceptions.InvalidCredentials, pika.exceptions.ProtocolSyntaxError) as e: print(f"Unrecoverable error: {str(e)}") raise # 直接抛出,终止程序 except Exception as e: # 处理其他未预见的异常,根据情况判断是否重试 print(f"Unexpected error: {str(e)}") retries += 1 time.sleep(retry_delay) raise RuntimeError("Max retries reached, unable to establish connection")
第三步:补充说明
- 对于Pika 1.0.0之后的版本,建议查看官方文档,后续版本可能已经将内部异常统一到
pika.exceptions下,减少异常处理的复杂度。 - 在判断是否可重试时,核心依据是异常是否由临时网络问题、服务端临时不可用导致,这类异常可以重试;而配置错误、凭证错误、协议错误属于不可恢复,需要修正配置后再运行。
附用户提供的应用日志:
2019-04-26T11:33:29.880310567Z ERROR:pika.adapters.utils.connection_workflow:Timeout while setting up AMQP to '█.█.█.█'/(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '█.█.█.█', ('█.█.█.█', ████)); ssl=False
2019-04-26T11:33:29.880880966Z ERROR:pika.adapters.utils.connection_workflow:AMQPConnector - reporting failure: AMQPConnectorAMQPHandshakeError: AMQPConnectorStackTimeout("Timeout during AMQP handshake'█.█.█.█'/(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '█.█.█.█', ('█.█.█.█', █)); ssl=False",)
2019-04-26T11:33:29.881053365Z ERROR:pika.adapters.utils.connection_workflow:AMQP connection workflow failed: AMQPConnectionWorkflowFailed: 1 exceptions in all; last exception - AMQPConnectorAMQPHandshakeError: AMQPConnectorStackTimeout("Timeout during AMQP handshake'█.█.█.█'/(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '█.█.█.█', ('█.█.█.█', ████)); ssl=False",); first exception - None.
2019-04-26T11:33:29.881150165Z ERROR:pika.adapters.utils.connection_workflow:AMQPConnectionWorkflow - reporting failure: AMQPConnectionWorkflowFailed: 1 exceptions in all; last exception - AMQPConnectorAMQPHandshakeError: AMQPConnectorStackTimeout("Timeout during AMQP handshake'█.█.█.█'/(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '█.█.█.█', ('█.█.█.█', ████)); ssl=False",); first exception - None
2019-04-26T11:33:29.881503064Z ERROR:pika.adapters.blocking_connection:Connection workflow failed: AMQPConnectionWorkflowFailed: 1 exceptions in all; last exception - AMQPConnectorAMQPHandshakeError: AMQPConnectorStackTimeout("Timeout during AMQP handshake'█.█.█.█'/(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '█.█.█.█', ('█.█.█.█', ████)); ssl=False",); first exception - None
2019-04-26T11:33:29.882705661Z ERROR:pika.adapters.blocking_connection:Error in _create_connection().
2019-04-26T11:33:29.882720061Z Traceback (most recent call last):
2019-04-26T11:33:29.882724561Z File "/usr/lib/python3.6/site-packages/pika/adapters/blocking_connection.py", line 451, in _create_connection
2019-04-26T11:33:29.882728961Z raise self._reap_last_connection_workflow_error(error)
2019-04-26T11:33:29.882732761Z pika.adapters.utils.connection_workflow.AMQPConnectorStackTimeout: Timeout during AMQP handshake'█.█.█.█'/(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '█.█.█.█', ('█.█.█.█', ████)); ssl=False
2019-04-26T11:33:29.883257859Z ERROR:root:AMQPConnectorStackTimeout Timeout during AMQP handshake'█.█.█.█'/(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '█.█.█.█', ('█.█.█.█', ████)); ssl=False
2019-04-26T11:33:29.883273859Z Traceback (most recent call last):
2019-04-26T11:33:29.883278359Z File "main.py", line 143, in <module>
2019-04-26T11:33:29.883282559Z main()
2019-04-26T11:33:29.883286259Z File "main.py", line 118, in main
2019-04-26T11:33:29.883290059Z with pika.BlockingConnection(parameters=pika.URLParameters(██████████)) as connection:
2019-04-26T11:33:29.883293959Z File "/usr/lib/python3.6/site-packages/pika/adapters/blocking_connection.py", line 360, in init
2019-04-26T11:33:29.883307559Z self._impl = self._create_connection(parameters, _impl_class)
2019-04-26T11:33:29.883311659Z File "/usr/lib/python3.6/site-packages/pika/adapters/blocking_connection.py", line 451, in _create_connection
2019-04-26T11:33:29.883315459Z raise self._reap_last_connection_workflow_error(error)
2019-04-26T11:33:29.883319059Z pika.adapters.utils.connection_workflow.AMQPConnectorStackTimeout: Timeout during AMQP handshake'█.█.█.█'/(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '█.█.█.█', ('█.█.█.█', ████)); ssl=False
2019-04-26T11:33:29.883323159Z Traceback (most recent call last):
2019-04-26T11:33:29.883326759Z File "main.py", line 143, in <module>
2019-04-26T11:33:29.883465559Z main()
2019-04-26T11:33:29.883473059Z File "main.py", line 118, in main
2019-04-26T11:33:29.883635558Z with pika.BlockingConnection(parameters=pika.URLParameters(██████████)) as connection:
2019-04-26T11:33:29.883650458Z File "/usr/lib/python3.6/site-packages/pika/adapters/blocking_connection.py", line 360, in init
2019-04-26T11:33:29.883894657Z self._impl = self._create_connection(parameters, _impl_class)
2019-04-26T11:33:29.883902657Z File "/usr/lib/python3.6/site-packages/pika/adapters/blocking_connection.py", line 451, in _create_connection
2019-04-26T11:33:29.884212657Z raise self._reap_last_connection_workflow_error(error)
2019-04-26T11:33:29.884222357Z pika.adapters.utils.connection_workflow.AMQPConnectorStackTimeout: Timeout during AMQP handshake'█.█.█.█'/(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '█.█.█.█', ('█.█.█.█', ████)); ssl=False
内容的提问来源于stack exchange,提问作者Ian Goldby

