sycommon-python-lib 0.1.33__py3-none-any.whl → 0.1.34__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.

Potentially problematic release.


This version of sycommon-python-lib might be problematic. Click here for more details.

@@ -80,7 +80,7 @@ class RabbitMQClient:
80
80
  self._exchange_exists = False
81
81
  self._queue_exists = False
82
82
  self._queue_bound = False
83
- self._is_consuming = False # 核心消费状态标志
83
+ self._is_consuming = False
84
84
  self._closed = False
85
85
  self._consumer_tag: Optional[ConsumerTag] = None
86
86
  self._last_activity_timestamp = asyncio.get_event_loop().time()
@@ -98,6 +98,8 @@ class RabbitMQClient:
98
98
 
99
99
  # 消息处理跟踪
100
100
  self._tracking_messages: Dict[str, Dict[str, Any]] = {}
101
+ # 状态保护锁
102
+ self._state_lock = asyncio.Lock()
101
103
 
102
104
  @property
103
105
  def is_connected(self) -> bool:
@@ -115,11 +117,12 @@ class RabbitMQClient:
115
117
  """更新最后消息处理时间戳"""
116
118
  self._last_message_processed = asyncio.get_event_loop().time()
117
119
 
118
- def _set_is_consuming(self, value: bool) -> None:
119
- """安全更新消费状态并记录日志"""
120
- if self._is_consuming != value:
121
- logger.info(f"消费状态变更: {self._is_consuming} {value}")
122
- self._is_consuming = value
120
+ async def _set_is_consuming(self, value: bool) -> None:
121
+ """安全更新消费状态并记录日志(带锁保护)"""
122
+ async with self._state_lock:
123
+ if self._is_consuming != value:
124
+ logger.info(f"消费状态变更: {self._is_consuming} {value}")
125
+ self._is_consuming = value
123
126
 
124
127
  async def _get_channel(self) -> AbstractChannel:
125
128
  """从通道池获取通道(使用上下文管理器)"""
@@ -200,7 +203,7 @@ class RabbitMQClient:
200
203
  self._exchange_exists = False
201
204
  self._queue_exists = False
202
205
  self._queue_bound = False
203
- self._set_is_consuming(False) # 连接时先停止消费
206
+ await self._set_is_consuming(False)
204
207
 
205
208
  retries = 0
206
209
  last_exception = None
@@ -312,7 +315,6 @@ class RabbitMQClient:
312
315
  current_time = asyncio.get_event_loop().time()
313
316
  # 清理消息跟踪记录
314
317
  if self._tracking_messages:
315
- # 1. 清理已确认的消息
316
318
  acked_ids = [
317
319
  msg_id for msg_id, info in self._tracking_messages.items()
318
320
  if info.get('acked', False)
@@ -322,28 +324,38 @@ class RabbitMQClient:
322
324
  if acked_ids:
323
325
  logger.info(f"清理了 {len(acked_ids)} 条已确认消息记录")
324
326
 
325
- # 检查消费停滞
327
+ # 检查消费停滞(仅当消费状态为 True 时才处理)
326
328
  if self._is_consuming:
327
329
  if current_time - self._last_message_processed > self.consumption_stall_threshold:
328
330
  if self._tracking_messages:
329
331
  logger.warning(
330
332
  f"消费停滞,但有 {len(self._tracking_messages)} 个消息正在处理,暂不重启")
331
333
  else:
332
- # 无有效消息,重启消费
333
334
  logger.info("消费停滞且无消息处理,重启消费")
334
- await self.stop_consuming()
335
- await asyncio.sleep(1)
336
- await self.start_consuming()
337
-
335
+ # 重启消费时增加异常捕获,确保状态回滚
336
+ try:
337
+ await self.stop_consuming()
338
+ await asyncio.sleep(1)
339
+ # 重启前检查处理器是否存在
340
+ if self.message_handler:
341
+ await self.start_consuming()
342
+ else:
343
+ logger.error("消费处理器已丢失,无法重启消费")
344
+ except Exception as e:
345
+ logger.error(
346
+ f"重启消费失败: {str(e)}", exc_info=True)
347
+ # 回滚状态:标记为未消费,避免一直拒绝消息
348
+ await self._set_is_consuming(False)
338
349
  except Exception as e:
339
- logger.error(f"监控任务出错: {str(e)}")
340
- await asyncio.sleep(1)
350
+ logger.error(f"监控任务出错: {str(e)}", exc_info=True)
341
351
 
342
352
  await asyncio.sleep(60)
343
353
 
344
354
  self._monitor_task = asyncio.create_task(monitor())
345
355
 
346
356
  async def _recreate_channel(self) -> None:
357
+ # 重建前先标记为未消费
358
+ await self._set_is_consuming(False)
347
359
  try:
348
360
  self.channel = await self._get_channel()
349
361
  await self.channel.set_qos(prefetch_count=self.prefetch_count)
@@ -353,16 +365,22 @@ class RabbitMQClient:
353
365
  if self.queue_name:
354
366
  self.queue = await self.channel.get_queue(self.queue_name)
355
367
  if self.queue and self.exchange:
356
- await self._bind_queue(self.channel, self.queue, self.exchange)
357
-
358
- # 重新开始消费
359
- if self.message_handler:
368
+ bound = await self._bind_queue(self.channel, self.queue, self.exchange)
369
+ if not bound:
370
+ raise Exception("队列绑定失败,通道重建不完整")
371
+
372
+ # 重新开始消费(确保状态正确恢复)
373
+ async with self._state_lock:
374
+ has_handler = self.message_handler is not None
375
+ if has_handler:
360
376
  await self.start_consuming()
361
377
 
362
378
  logger.info("通道已重建并恢复服务")
363
379
  self._update_activity_timestamp()
364
380
  except Exception as e:
365
- logger.error(f"通道重建失败: {str(e)},触发重连")
381
+ logger.error(f"通道重建失败: {str(e)},触发重连", exc_info=True)
382
+ # 重建失败时,确保消费状态为 False
383
+ await self._set_is_consuming(False)
366
384
  await self.connect(force_reconnect=True)
367
385
 
368
386
  def _start_keepalive(self) -> None:
@@ -422,7 +440,7 @@ class RabbitMQClient:
422
440
  async def close(self) -> None:
423
441
  """关闭客户端并释放资源"""
424
442
  self._closed = True
425
- self._set_is_consuming(False)
443
+ await self._set_is_consuming(False)
426
444
 
427
445
  # 取消所有任务
428
446
  for task in [self._keepalive_task, self._reconnect_task,
@@ -508,16 +526,18 @@ class RabbitMQClient:
508
526
 
509
527
  raise Exception(f"消息发布失败,经过{retry_count}次重试仍未成功")
510
528
 
511
- def set_message_handler(self, handler):
512
- self.message_handler = handler
529
+ async def set_message_handler(self, handler):
530
+ async with self._state_lock:
531
+ self.message_handler = handler
513
532
 
514
533
  async def start_consuming(self) -> ConsumerTag:
515
- if self._is_consuming:
516
- logger.info("已经在消费中,返回现有consumer_tag")
517
- if self._consumer_tag:
518
- return self._consumer_tag
519
- logger.warning("检测到消费状态异常(无consumer_tag),重置状态后重试")
520
- self._set_is_consuming(False)
534
+ async with self._state_lock:
535
+ if self._is_consuming:
536
+ logger.info("已经在消费中,返回现有consumer_tag")
537
+ if self._consumer_tag:
538
+ return self._consumer_tag
539
+ logger.warning("检测到消费状态异常(无consumer_tag),重置状态后重试")
540
+ self._is_consuming = False
521
541
 
522
542
  if not self.is_connected:
523
543
  await self.connect()
@@ -525,8 +545,9 @@ class RabbitMQClient:
525
545
  if not self.queue:
526
546
  raise Exception("队列未初始化,无法开始消费")
527
547
 
528
- if not self.message_handler:
529
- raise Exception("未设置消息处理函数")
548
+ async with self._state_lock:
549
+ if not self.message_handler:
550
+ raise Exception("未设置消息处理函数")
530
551
 
531
552
  try:
532
553
  self._consumer_tag = await self.queue.consume(
@@ -537,12 +558,13 @@ class RabbitMQClient:
537
558
  if not self._consumer_tag:
538
559
  raise Exception("未能获取到有效的consumer_tag")
539
560
 
540
- self._set_is_consuming(True)
561
+ await self._set_is_consuming(True)
541
562
  logger.info(
542
563
  f"消费者已启动,队列: {self.actual_queue_name}, tag: {self._consumer_tag}")
543
564
  return self._consumer_tag
544
565
  except Exception as e:
545
- self._set_is_consuming(False)
566
+ # 异常时强制设置为未消费
567
+ await self._set_is_consuming(False)
546
568
  logger.error(f"启动消费失败: {str(e)}", exc_info=True)
547
569
  raise
548
570
 
@@ -565,7 +587,7 @@ class RabbitMQClient:
565
587
  if not self._is_consuming:
566
588
  return
567
589
 
568
- self._set_is_consuming(False)
590
+ await self._set_is_consuming(False)
569
591
 
570
592
  if self._consumer_tag and self.queue:
571
593
  await self._safe_cancel_consumer()
@@ -602,10 +624,19 @@ class RabbitMQClient:
602
624
  return message.body.decode('utf-8')
603
625
 
604
626
  async def _message_wrapper(self, message: AbstractIncomingMessage) -> None:
605
- if not self.message_handler or not self._is_consuming:
606
- logger.warning("未设置消息处理器或已停止消费,拒绝消息,重新放到队列")
627
+ # 先通过锁获取当前状态,避免并发修改导致的判断错误
628
+ async with self._state_lock:
629
+ has_handler = self.message_handler is not None
630
+ is_consuming = self._is_consuming
631
+
632
+ if not has_handler or not is_consuming:
633
+ logger.warning(
634
+ f"拒绝消息: message_handler={'存在' if has_handler else '不存在'}, "
635
+ f"is_consuming={is_consuming},消息ID: {message.message_id or str(id(message))}"
636
+ )
607
637
  try:
608
638
  await message.reject(requeue=True)
639
+ await asyncio.sleep(3)
609
640
  except Exception as e:
610
641
  logger.error(f"拒绝消息失败: {e}")
611
642
  return
@@ -443,7 +443,7 @@ class RabbitMQService:
443
443
  handler = cls.default_message_handler
444
444
 
445
445
  # 设置消息处理器
446
- client.set_message_handler(handler)
446
+ await client.set_message_handler(handler)
447
447
 
448
448
  # 确保客户端已连接
449
449
  start_time = asyncio.get_event_loop().time()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sycommon-python-lib
3
- Version: 0.1.33
3
+ Version: 0.1.34
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -35,9 +35,9 @@ 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=mI_e8iP2F9_oYMPvrP9wYW5x1wtLPLaxpNJ9719pDs4,27899
38
+ sycommon/rabbitmq/rabbitmq_client.py,sha256=n3c1W31S1NAOkQO2UDpQYgE7Ex8N2hyZrqwPpyxEijU,29733
39
39
  sycommon/rabbitmq/rabbitmq_pool.py,sha256=_NMOO4CZy-I_anMqpzfYinz-8373_rg5FM9eqzdjGyU,3598
40
- sycommon/rabbitmq/rabbitmq_service.py,sha256=fP3kslCL_LfYHeM7D88C8hDFeq00bdipSh4q-LU23mo,30193
40
+ sycommon/rabbitmq/rabbitmq_service.py,sha256=5BrqF_3PwEMbqs8AVhSqFpqzo3GrIftafMX_tCmFv8E,30199
41
41
  sycommon/sse/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
42
  sycommon/sse/event.py,sha256=k_rBJy23R7crtzQeetT0Q73D8o5-5p-eESGSs_BPOj0,2797
43
43
  sycommon/sse/sse.py,sha256=__CfWEcYxOxQ-HpLor4LTZ5hLWqw9-2X7CngqbVHsfw,10128
@@ -52,8 +52,8 @@ 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.33.dist-info/METADATA,sha256=UfJB9N7EShz-rTDuKzcQcVZ-Wx-4liFN9pgcBONggyk,7037
56
- sycommon_python_lib-0.1.33.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
57
- sycommon_python_lib-0.1.33.dist-info/entry_points.txt,sha256=q_h2nbvhhmdnsOUZEIwpuoDjaNfBF9XqppDEmQn9d_A,46
58
- sycommon_python_lib-0.1.33.dist-info/top_level.txt,sha256=98CJ-cyM2WIKxLz-Pf0AitWLhJyrfXvyY8slwjTXNuc,17
59
- sycommon_python_lib-0.1.33.dist-info/RECORD,,
55
+ sycommon_python_lib-0.1.34.dist-info/METADATA,sha256=8m47X4r_A5oq9e1CjQaBkt5gdRTblwW7qyln8kQzC0c,7037
56
+ sycommon_python_lib-0.1.34.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
57
+ sycommon_python_lib-0.1.34.dist-info/entry_points.txt,sha256=q_h2nbvhhmdnsOUZEIwpuoDjaNfBF9XqppDEmQn9d_A,46
58
+ sycommon_python_lib-0.1.34.dist-info/top_level.txt,sha256=98CJ-cyM2WIKxLz-Pf0AitWLhJyrfXvyY8slwjTXNuc,17
59
+ sycommon_python_lib-0.1.34.dist-info/RECORD,,