sycommon-python-lib 0.1.44__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.
@@ -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. 消息发布支持重试,消费支持手动ACK/NACK
32
- 4. 兼容JSON/字符串/字典消息格式
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
- # 4. 声明队列(如果配置了队列名)
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
- """安全重连:固定15秒间隔,避免重复任务"""
219
- # 检查是否已有重连任务在运行
220
- if self._current_reconnect_task and not self._current_reconnect_task.done():
221
- SYLogger.debug("已有重连任务在运行,跳过重复触发")
222
- return
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
- # 固定15秒重连间隔
229
- SYLogger.info(f"将在15秒后尝试重连...")
230
- await asyncio.sleep(self._RECONNECT_INTERVAL)
224
+ async with self._reconnect_task_lock:
225
+ if self._closed or await self.is_connected:
226
+ SYLogger.debug("客户端已关闭或已连接,取消重连")
227
+ return
231
228
 
232
- if self._closed or await self.is_connected:
233
- return
229
+ # 3. 固定15秒重连间隔(避免频繁重试)
230
+ SYLogger.info(f"将在15秒后尝试重连...")
231
+ await asyncio.sleep(self._RECONNECT_INTERVAL)
234
232
 
235
- try:
236
- self._current_reconnect_task = asyncio.create_task(
237
- self.connect())
238
- await self._current_reconnect_task
239
- except Exception as e:
240
- SYLogger.warning(f"重连失败: {str(e)}")
241
- # 重连失败后,继续触发下一次重连(仍保持15秒间隔)
242
- asyncio.create_task(self._safe_reconnect())
243
- finally:
244
- self._current_reconnect_task = None
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.connect())
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
- 发布消息(支持自动重试、JSON序列化)
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
- await asyncio.sleep(0.5 * (2 ** retry))
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
 
@@ -35,7 +35,7 @@ class NacosService(metaclass=SingletonMeta):
35
35
 
36
36
  # 配置参数
37
37
  self.max_retries = self.nacos_config.get('maxRetries', 5)
38
- self.retry_delay = self.nacos_config.get('retryDelay', 1)
38
+ self.retry_delay = self.nacos_config.get('retryDelay', 5)
39
39
  self.max_retry_delay = self.nacos_config.get('maxRetryDelay', 30)
40
40
  # 心跳间隔:优先从配置读取,默认15秒(可通过配置修改)
41
41
  self.heartbeat_interval = self.nacos_config.get(
@@ -51,11 +51,13 @@ class NacosService(metaclass=SingletonMeta):
51
51
  self.max_long_term_retries = self.nacos_config.get(
52
52
  'maxLongTermRetries', -1) # -1表示无限重试
53
53
 
54
- # 注册验证配置
54
+ # 注册验证配置:优化默认值(增加次数+延长间隔)
55
55
  self.registration_verify_count = self.nacos_config.get(
56
56
  'registrationVerifyCount', 1) # 验证次数
57
57
  self.registration_verify_interval = self.nacos_config.get(
58
58
  'registrationVerifyInterval', 1) # 验证间隔
59
+ self.registration_post_delay = self.nacos_config.get(
60
+ 'registrationPostDelay', 3) # 注册后延迟3秒再开始验证
59
61
 
60
62
  self.real_ip = self.get_service_ip(self.host)
61
63
  self._long_term_retry_count = 0 # 长期重试计数器
@@ -300,12 +302,12 @@ class NacosService(metaclass=SingletonMeta):
300
302
  if not register_success:
301
303
  raise RuntimeError("nacos:服务注册请求失败")
302
304
 
303
- # 注册请求发送成功后,等待一小段时间让Nacos服务器处理
305
+ # 关键优化1:注册请求发送后,延迟一段时间再验证(默认3秒)
304
306
  SYLogger.info(
305
- f"nacos:服务注册请求已发送,等待 {self.registration_verify_interval} 秒后验证")
306
- time.sleep(self.registration_verify_interval)
307
+ f"nacos:服务注册请求已发送,延迟 {self.registration_post_delay} 秒后开始验证(确保Nacos服务器完成实例写入)")
308
+ time.sleep(self.registration_post_delay)
307
309
 
308
- # 多次验证服务是否真正注册成功
310
+ # 关键优化2:多次验证服务是否真正注册成功(默认3次,每次间隔2秒)
309
311
  registered = self.verify_registration()
310
312
 
311
313
  # 带锁更新注册状态
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sycommon-python-lib
3
- Version: 0.1.44
3
+ Version: 0.1.45
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -35,7 +35,7 @@ sycommon/models/mqlistener_config.py,sha256=vXp2uMmd0XQ5B9noSRXWHewTy-juQ2y7IsWt
35
35
  sycommon/models/mqmsg_model.py,sha256=cxn0M5b0utQK6crMYmL-1waeGYHvK3AlGaRy23clqTE,277
36
36
  sycommon/models/mqsend_config.py,sha256=NQX9dc8PpuquMG36GCVhJe8omAW1KVXXqr6lSRU6D7I,268
37
37
  sycommon/models/sso_user.py,sha256=i1WAN6k5sPcPApQEdtjpWDy7VrzWLpOrOQewGLGoGIw,2702
38
- sycommon/rabbitmq/rabbitmq_client.py,sha256=aRS7sYN4RAJ210Bl-Bh0qR7mXpaag_5YygNXz6ryhtQ,19677
38
+ sycommon/rabbitmq/rabbitmq_client.py,sha256=dKpiptV892VbW3fErAoRZSE9UVVBZvbVPM3qPu8rQIk,21573
39
39
  sycommon/rabbitmq/rabbitmq_pool.py,sha256=ckHEpvPXS4TdHRS_2eGyiQ7kej3P7Wnyk3nttAjk04o,17724
40
40
  sycommon/rabbitmq/rabbitmq_service.py,sha256=L7SKf8Ws2wZvF0YGU1ZUiqg3z_viSNmMR0Zz4_5jBSY,39775
41
41
  sycommon/sse/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -46,14 +46,14 @@ sycommon/synacos/example.py,sha256=61XL03tU8WTNOo3FUduf93F2fAwah1S0lbH1ufhRhRk,5
46
46
  sycommon/synacos/example2.py,sha256=adUaru3Hy482KrOA17DfaC4nwvLj8etIDS_KrWLWmCU,4811
47
47
  sycommon/synacos/feign.py,sha256=-2tuGCqoSM3ddSoSz7h1RJTB06hn8K26v_1ev4qLsTU,7728
48
48
  sycommon/synacos/feign_client.py,sha256=JxzxohrsscQNlAjRVo_3ZQrMQSfVHFOtRYyEnP6sDGk,15205
49
- sycommon/synacos/nacos_service.py,sha256=Hxd3fQOR53iujUjCboJoQum5vAXxQ9sdc8YlDug1OF0,35092
49
+ sycommon/synacos/nacos_service.py,sha256=2m1ZxIii3r657kQJfp7C7I5bxBUEGDweYMfloUUmBSw,35389
50
50
  sycommon/synacos/param.py,sha256=KcfSkxnXOa0TGmCjY8hdzU9pzUsA8-4PeyBKWI2-568,1765
51
51
  sycommon/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
52
  sycommon/tools/docs.py,sha256=OPj2ETheuWjXLyaXtaZPbwmJKfJaYXV5s4XMVAUNrms,1607
53
53
  sycommon/tools/snowflake.py,sha256=DdEj3T5r5OEvikp3puxqmmmz6BrggxomoSlnsRFb5dM,1174
54
54
  sycommon/tools/timing.py,sha256=OiiE7P07lRoMzX9kzb8sZU9cDb0zNnqIlY5pWqHcnkY,2064
55
- sycommon_python_lib-0.1.44.dist-info/METADATA,sha256=e_42ggxA1f4lcE0zFt2uvEPbT_Q5pANx_Dpb6HFIrVQ,7037
56
- sycommon_python_lib-0.1.44.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
57
- sycommon_python_lib-0.1.44.dist-info/entry_points.txt,sha256=q_h2nbvhhmdnsOUZEIwpuoDjaNfBF9XqppDEmQn9d_A,46
58
- sycommon_python_lib-0.1.44.dist-info/top_level.txt,sha256=98CJ-cyM2WIKxLz-Pf0AitWLhJyrfXvyY8slwjTXNuc,17
59
- sycommon_python_lib-0.1.44.dist-info/RECORD,,
55
+ sycommon_python_lib-0.1.45.dist-info/METADATA,sha256=z1pOqekth0xbqc4RfCkk5CHHm3b4FS4R0Tcy3BxUYus,7037
56
+ sycommon_python_lib-0.1.45.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
57
+ sycommon_python_lib-0.1.45.dist-info/entry_points.txt,sha256=q_h2nbvhhmdnsOUZEIwpuoDjaNfBF9XqppDEmQn9d_A,46
58
+ sycommon_python_lib-0.1.45.dist-info/top_level.txt,sha256=98CJ-cyM2WIKxLz-Pf0AitWLhJyrfXvyY8slwjTXNuc,17
59
+ sycommon_python_lib-0.1.45.dist-info/RECORD,,