sycommon-python-lib 0.1.43__py3-none-any.whl → 0.1.45__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sycommon/rabbitmq/rabbitmq_client.py +72 -49
- sycommon/rabbitmq/rabbitmq_pool.py +332 -294
- sycommon/rabbitmq/rabbitmq_service.py +0 -4
- sycommon/services.py +2 -1
- sycommon/synacos/feign.py +9 -8
- sycommon/synacos/nacos_service.py +73 -52
- {sycommon_python_lib-0.1.43.dist-info → sycommon_python_lib-0.1.45.dist-info}/METADATA +7 -7
- {sycommon_python_lib-0.1.43.dist-info → sycommon_python_lib-0.1.45.dist-info}/RECORD +11 -11
- {sycommon_python_lib-0.1.43.dist-info → sycommon_python_lib-0.1.45.dist-info}/WHEEL +0 -0
- {sycommon_python_lib-0.1.43.dist-info → sycommon_python_lib-0.1.45.dist-info}/entry_points.txt +0 -0
- {sycommon_python_lib-0.1.43.dist-info → sycommon_python_lib-0.1.45.dist-info}/top_level.txt +0 -0
|
@@ -9,16 +9,13 @@ from aio_pika.abc import (
|
|
|
9
9
|
AbstractQueue,
|
|
10
10
|
AbstractIncomingMessage,
|
|
11
11
|
ConsumerTag,
|
|
12
|
-
AbstractRobustConnection
|
|
12
|
+
AbstractRobustConnection,
|
|
13
13
|
)
|
|
14
14
|
from sycommon.rabbitmq.rabbitmq_pool import RabbitMQConnectionPool
|
|
15
15
|
from sycommon.logging.kafka_log import SYLogger
|
|
16
16
|
from sycommon.models.mqmsg_model import MQMsgModel
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
# 最大重试次数限制
|
|
20
|
-
MAX_RETRY_COUNT = 3
|
|
21
|
-
|
|
22
19
|
logger = SYLogger
|
|
23
20
|
|
|
24
21
|
|
|
@@ -27,10 +24,10 @@ class RabbitMQClient:
|
|
|
27
24
|
RabbitMQ 客户端(支持消息发布、消费、自动重连、异常重试)
|
|
28
25
|
核心特性:
|
|
29
26
|
1. 基于连接池复用资源,性能优化
|
|
30
|
-
2.
|
|
31
|
-
3.
|
|
32
|
-
4.
|
|
33
|
-
5.
|
|
27
|
+
2. 连接/通道失效时自动重建,高可用(限制并发重连)
|
|
28
|
+
3. 消息发布支持重试+mandatory机制+超时控制,确保路由有效
|
|
29
|
+
4. 消费支持手动ACK/NACK
|
|
30
|
+
5. 兼容JSON/字符串/字典消息格式
|
|
34
31
|
"""
|
|
35
32
|
|
|
36
33
|
def __init__(
|
|
@@ -45,7 +42,6 @@ class RabbitMQClient:
|
|
|
45
42
|
auto_parse_json: bool = True,
|
|
46
43
|
create_if_not_exists: bool = True,
|
|
47
44
|
prefetch_count: int = 2,
|
|
48
|
-
# 兼容旧代码参数(无需使用)
|
|
49
45
|
**kwargs,
|
|
50
46
|
):
|
|
51
47
|
# 依赖注入:连接池(必须已初始化)
|
|
@@ -87,10 +83,8 @@ class RabbitMQClient:
|
|
|
87
83
|
self._connect_lock = asyncio.Lock()
|
|
88
84
|
# 跟踪连接关闭回调(用于后续移除)
|
|
89
85
|
self._conn_close_callback: Optional[Callable] = None
|
|
90
|
-
#
|
|
86
|
+
# 控制重连频率的信号量(限制并发重连数,默认1个)
|
|
91
87
|
self._reconnect_semaphore = asyncio.Semaphore(1)
|
|
92
|
-
# 重连冷却时间(秒)
|
|
93
|
-
self._reconnect_cooldown = 3
|
|
94
88
|
# 固定重连间隔15秒(全局统一)
|
|
95
89
|
self._RECONNECT_INTERVAL = 15
|
|
96
90
|
# 重连任务锁(确保同一时间只有一个重连任务)
|
|
@@ -140,7 +134,7 @@ class RabbitMQClient:
|
|
|
140
134
|
self._conn_close_callback = None
|
|
141
135
|
|
|
142
136
|
try:
|
|
143
|
-
#
|
|
137
|
+
# 从连接池获取通道+连接(连接池返回的是 RobustChannel)
|
|
144
138
|
self._channel, self._channel_conn = await self.connection_pool.acquire_channel()
|
|
145
139
|
|
|
146
140
|
def on_conn_closed(conn: AbstractRobustConnection, exc: Optional[BaseException]):
|
|
@@ -164,7 +158,11 @@ class RabbitMQClient:
|
|
|
164
158
|
await self._channel.set_qos(prefetch_count=self.prefetch_count)
|
|
165
159
|
SYLogger.debug(f"设置预取计数: {self.prefetch_count}")
|
|
166
160
|
|
|
167
|
-
# 3.
|
|
161
|
+
# 3. 低版本 RobustChannel 说明:默认启用异步发布确认,无显式确认方法
|
|
162
|
+
SYLogger.debug(
|
|
163
|
+
"基于 RobustChannel 异步发布确认(低版本 aio-pika 不支持显式确认方法)")
|
|
164
|
+
|
|
165
|
+
# 4. 声明交换机
|
|
168
166
|
self._exchange = await self._channel.declare_exchange(
|
|
169
167
|
name=self.exchange_name,
|
|
170
168
|
type=self.exchange_type,
|
|
@@ -175,7 +173,7 @@ class RabbitMQClient:
|
|
|
175
173
|
SYLogger.info(
|
|
176
174
|
f"交换机初始化成功: {self.exchange_name}(类型: {self.exchange_type.value})")
|
|
177
175
|
|
|
178
|
-
#
|
|
176
|
+
# 5. 声明队列(如果配置了队列名)
|
|
179
177
|
if self.queue_name:
|
|
180
178
|
self._queue = await self._channel.declare_queue(
|
|
181
179
|
name=self.queue_name,
|
|
@@ -215,33 +213,38 @@ class RabbitMQClient:
|
|
|
215
213
|
raise
|
|
216
214
|
|
|
217
215
|
async def _safe_reconnect(self):
|
|
218
|
-
"""
|
|
219
|
-
#
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
async with self._reconnect_task_lock:
|
|
225
|
-
if self._closed or await self.is_connected:
|
|
216
|
+
"""安全重连:信号量控制并发+固定15秒间隔,避免短时间大量重连"""
|
|
217
|
+
# 1. 信号量控制:限制同时进行的重连任务数(默认1个)
|
|
218
|
+
async with self._reconnect_semaphore:
|
|
219
|
+
# 2. 检查是否已有重连任务在运行(双重保障)
|
|
220
|
+
if self._current_reconnect_task and not self._current_reconnect_task.done():
|
|
221
|
+
SYLogger.debug("已有重连任务在运行,跳过重复触发")
|
|
226
222
|
return
|
|
227
223
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
224
|
+
async with self._reconnect_task_lock:
|
|
225
|
+
if self._closed or await self.is_connected:
|
|
226
|
+
SYLogger.debug("客户端已关闭或已连接,取消重连")
|
|
227
|
+
return
|
|
231
228
|
|
|
232
|
-
|
|
233
|
-
|
|
229
|
+
# 3. 固定15秒重连间隔(避免频繁重试)
|
|
230
|
+
SYLogger.info(f"将在15秒后尝试重连...")
|
|
231
|
+
await asyncio.sleep(self._RECONNECT_INTERVAL)
|
|
234
232
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
233
|
+
if self._closed or await self.is_connected:
|
|
234
|
+
SYLogger.debug("重连等待期间客户端状态变化,取消重连")
|
|
235
|
+
return
|
|
236
|
+
|
|
237
|
+
try:
|
|
238
|
+
# 4. 执行重连
|
|
239
|
+
SYLogger.info("开始重连RabbitMQ客户端...")
|
|
240
|
+
self._current_reconnect_task = asyncio.create_task(
|
|
241
|
+
self.connect())
|
|
242
|
+
await self._current_reconnect_task
|
|
243
|
+
except Exception as e:
|
|
244
|
+
SYLogger.warning(f"重连失败: {str(e)}")
|
|
245
|
+
# 重连失败后,不主动触发下一次(等待连接关闭回调再次触发,避免死循环)
|
|
246
|
+
finally:
|
|
247
|
+
self._current_reconnect_task = None
|
|
245
248
|
|
|
246
249
|
async def set_message_handler(
|
|
247
250
|
self,
|
|
@@ -315,7 +318,7 @@ class RabbitMQClient:
|
|
|
315
318
|
# 检查连接状态,失效则触发重连
|
|
316
319
|
if not await self.is_connected:
|
|
317
320
|
SYLogger.warning("连接已失效,触发客户端重连")
|
|
318
|
-
asyncio.create_task(self.
|
|
321
|
+
asyncio.create_task(self._safe_reconnect())
|
|
319
322
|
|
|
320
323
|
# 3. 启动消费
|
|
321
324
|
self._consumer_tag = await self._queue.consume(consume_callback)
|
|
@@ -345,7 +348,7 @@ class RabbitMQClient:
|
|
|
345
348
|
retry_count: int = 3,
|
|
346
349
|
) -> None:
|
|
347
350
|
"""
|
|
348
|
-
发布消息(支持自动重试、
|
|
351
|
+
发布消息(支持自动重试、mandatory路由校验、5秒超时控制)
|
|
349
352
|
:param message_body: 消息体(字符串/字典/MQMsgModel)
|
|
350
353
|
:param headers: 消息头(可选)
|
|
351
354
|
:param content_type: 内容类型(默认application/json)
|
|
@@ -387,33 +390,53 @@ class RabbitMQClient:
|
|
|
387
390
|
SYLogger.warning(f"发布消息前连接失效,触发重连(retry: {retry})")
|
|
388
391
|
await self.connect()
|
|
389
392
|
|
|
390
|
-
#
|
|
391
|
-
await self._exchange.publish(
|
|
393
|
+
# 核心:发布消息(添加 mandatory=True 和 timeout=5.0)
|
|
394
|
+
publish_result = await self._exchange.publish(
|
|
392
395
|
message=message,
|
|
393
396
|
routing_key=self.routing_key or self.queue_name or "#",
|
|
397
|
+
mandatory=True, # 强制路由到至少一个队列,否则返回None
|
|
398
|
+
timeout=5.0 # 5秒超时控制,避免无限阻塞
|
|
394
399
|
)
|
|
400
|
+
|
|
401
|
+
# 处理 mandatory=True 结果:未路由到队列返回 None,直接抛出异常
|
|
402
|
+
if publish_result is None:
|
|
403
|
+
raise RuntimeError(
|
|
404
|
+
f"消息未找到匹配的队列(routing_key: {self.routing_key}),mandatory=True 触发失败"
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
# 低版本 RobustChannel 异步确认,无需显式等待,仅日志说明
|
|
395
408
|
SYLogger.info(
|
|
396
409
|
f"消息发布成功(retry: {retry}),routing_key: {self.routing_key},"
|
|
397
|
-
f"delivery_mode: {delivery_mode.value}"
|
|
410
|
+
f"delivery_mode: {delivery_mode.value},mandatory: True,timeout: 5.0s"
|
|
398
411
|
)
|
|
399
412
|
return
|
|
413
|
+
except asyncio.TimeoutError:
|
|
414
|
+
SYLogger.error(
|
|
415
|
+
f"消息发布超时(retry: {retry}/{retry_count-1}),超时时间: 5.0s"
|
|
416
|
+
)
|
|
417
|
+
except RuntimeError as e:
|
|
418
|
+
# 捕获 mandatory 未路由等业务异常
|
|
419
|
+
SYLogger.error(
|
|
420
|
+
f"消息发布业务失败(retry: {retry}/{retry_count-1}): {str(e)}"
|
|
421
|
+
)
|
|
400
422
|
except Exception as e:
|
|
401
423
|
SYLogger.error(
|
|
402
424
|
f"消息发布失败(retry: {retry}/{retry_count-1}): {str(e)}",
|
|
403
425
|
exc_info=True
|
|
404
426
|
)
|
|
405
|
-
#
|
|
427
|
+
# 清理失效状态,下次重试重连
|
|
406
428
|
self._exchange = None
|
|
407
|
-
|
|
408
|
-
|
|
429
|
+
# 指数退避重试间隔(0.5s, 1s, 2s...)
|
|
430
|
+
await asyncio.sleep(0.5 * (2 ** retry))
|
|
409
431
|
|
|
410
|
-
#
|
|
432
|
+
# 所有重试失败,抛出最终异常
|
|
411
433
|
raise RuntimeError(
|
|
412
|
-
f"消息发布失败(已重试{retry_count}次),routing_key: {self.routing_key}"
|
|
434
|
+
f"消息发布失败(已重试{retry_count}次),routing_key: {self.routing_key},"
|
|
435
|
+
f"mandatory: True,timeout: 5.0s"
|
|
413
436
|
)
|
|
414
437
|
|
|
415
438
|
async def close(self) -> None:
|
|
416
|
-
"""
|
|
439
|
+
"""关闭客户端(移除回调+释放资源)"""
|
|
417
440
|
self._closed = True
|
|
418
441
|
SYLogger.info("开始关闭RabbitMQ客户端...")
|
|
419
442
|
|