sycommon-python-lib 0.1.31__tar.gz → 0.1.33__tar.gz

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.

Files changed (64) hide show
  1. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/PKG-INFO +1 -1
  2. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/pyproject.toml +1 -1
  3. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/rabbitmq/rabbitmq_client.py +84 -77
  4. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/rabbitmq/rabbitmq_service.py +13 -13
  5. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/services.py +4 -0
  6. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/PKG-INFO +1 -1
  7. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/README.md +0 -0
  8. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/setup.cfg +0 -0
  9. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/command/cli.py +0 -0
  10. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/__init__.py +0 -0
  11. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/Config.py +0 -0
  12. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/DatabaseConfig.py +0 -0
  13. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/EmbeddingConfig.py +0 -0
  14. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/LLMConfig.py +0 -0
  15. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/MQConfig.py +0 -0
  16. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/RerankerConfig.py +0 -0
  17. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/__init__.py +0 -0
  18. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/database/base_db_service.py +0 -0
  19. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/database/database_service.py +0 -0
  20. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/health/__init__.py +0 -0
  21. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/health/health_check.py +0 -0
  22. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/health/metrics.py +0 -0
  23. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/health/ping.py +0 -0
  24. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/logging/__init__.py +0 -0
  25. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/logging/kafka_log.py +0 -0
  26. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/logging/logger_wrapper.py +0 -0
  27. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/logging/sql_logger.py +0 -0
  28. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/__init__.py +0 -0
  29. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/context.py +0 -0
  30. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/cors.py +0 -0
  31. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/docs.py +0 -0
  32. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/exception.py +0 -0
  33. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/middleware.py +0 -0
  34. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/monitor_memory.py +0 -0
  35. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/mq.py +0 -0
  36. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/timeout.py +0 -0
  37. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/traceid.py +0 -0
  38. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/__init__.py +0 -0
  39. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/base_http.py +0 -0
  40. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/log.py +0 -0
  41. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/mqlistener_config.py +0 -0
  42. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/mqmsg_model.py +0 -0
  43. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/mqsend_config.py +0 -0
  44. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/sso_user.py +0 -0
  45. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/rabbitmq/rabbitmq_pool.py +0 -0
  46. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/sse/__init__.py +0 -0
  47. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/sse/event.py +0 -0
  48. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/sse/sse.py +0 -0
  49. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/__init__.py +0 -0
  50. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/example.py +0 -0
  51. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/example2.py +0 -0
  52. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/feign.py +0 -0
  53. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/feign_client.py +0 -0
  54. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/nacos_service.py +0 -0
  55. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/param.py +0 -0
  56. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/tools/__init__.py +0 -0
  57. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/tools/docs.py +0 -0
  58. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/tools/snowflake.py +0 -0
  59. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/tools/timing.py +0 -0
  60. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/SOURCES.txt +0 -0
  61. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/dependency_links.txt +0 -0
  62. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/entry_points.txt +0 -0
  63. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/requires.txt +0 -0
  64. {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sycommon-python-lib
3
- Version: 0.1.31
3
+ Version: 0.1.33
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sycommon-python-lib"
3
- version = "0.1.31"
3
+ version = "0.1.33"
4
4
  description = "Add your description here"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -45,11 +45,6 @@ class RabbitMQClient:
45
45
  prefetch_count: int = 2,
46
46
  consumption_stall_threshold: int = 10
47
47
  ):
48
- """
49
- 初始化RabbitMQ客户端(依赖连接池)
50
-
51
- :param connection_pool: 连接池实例
52
- """
53
48
  # 连接池依赖
54
49
  self.connection_pool = connection_pool
55
50
 
@@ -85,7 +80,7 @@ class RabbitMQClient:
85
80
  self._exchange_exists = False
86
81
  self._queue_exists = False
87
82
  self._queue_bound = False
88
- self._is_consuming = False
83
+ self._is_consuming = False # 核心消费状态标志
89
84
  self._closed = False
90
85
  self._consumer_tag: Optional[ConsumerTag] = None
91
86
  self._last_activity_timestamp = asyncio.get_event_loop().time()
@@ -102,7 +97,7 @@ class RabbitMQClient:
102
97
  self._monitor_task: Optional[asyncio.Task] = None
103
98
 
104
99
  # 消息处理跟踪
105
- self._processing_message_ids: Set[str] = set()
100
+ self._tracking_messages: Dict[str, Dict[str, Any]] = {}
106
101
 
107
102
  @property
108
103
  def is_connected(self) -> bool:
@@ -120,19 +115,23 @@ class RabbitMQClient:
120
115
  """更新最后消息处理时间戳"""
121
116
  self._last_message_processed = asyncio.get_event_loop().time()
122
117
 
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
123
+
123
124
  async def _get_channel(self) -> AbstractChannel:
124
125
  """从通道池获取通道(使用上下文管理器)"""
125
126
  if not self.connection_pool.channel_pool:
126
127
  raise Exception("连接池未初始化,请先调用init_pools")
127
128
 
128
- # 使用async with获取通道,并通过变量返回
129
129
  async with self.connection_pool.channel_pool.acquire() as channel:
130
130
  return channel
131
131
 
132
132
  async def _check_exchange_exists(self, channel: AbstractChannel) -> bool:
133
133
  """检查交换机是否存在"""
134
134
  try:
135
- # 使用被动模式检查交换机
136
135
  await asyncio.wait_for(
137
136
  channel.declare_exchange(
138
137
  name=self.exchange_name,
@@ -150,7 +149,6 @@ class RabbitMQClient:
150
149
  if not self.queue_name:
151
150
  return False
152
151
  try:
153
- # 使用被动模式检查队列
154
152
  await asyncio.wait_for(
155
153
  channel.declare_queue(
156
154
  name=self.queue_name,
@@ -186,19 +184,15 @@ class RabbitMQClient:
186
184
  return False
187
185
 
188
186
  async def connect(self, force_reconnect: bool = False, declare_queue: bool = True) -> None:
189
- """
190
- 从连接池获取资源并初始化(交换机、队列)
191
- """
192
- logger.debug(
187
+ """从连接池获取资源并初始化(交换机、队列)"""
188
+ logger.info(
193
189
  f"连接参数 - force_reconnect={force_reconnect}, "
194
190
  f"declare_queue={declare_queue}, create_if_not_exists={self.create_if_not_exists}"
195
191
  )
196
192
 
197
- # 如果已连接且不强制重连,则直接返回
198
193
  if self.is_connected and not force_reconnect:
199
194
  return
200
195
 
201
- # 取消正在进行的重连任务
202
196
  if self._reconnect_task and not self._reconnect_task.done():
203
197
  self._reconnect_task.cancel()
204
198
 
@@ -206,13 +200,13 @@ class RabbitMQClient:
206
200
  self._exchange_exists = False
207
201
  self._queue_exists = False
208
202
  self._queue_bound = False
203
+ self._set_is_consuming(False) # 连接时先停止消费
209
204
 
210
205
  retries = 0
211
206
  last_exception = None
212
207
 
213
208
  while retries < self.max_reconnection_attempts:
214
209
  try:
215
- # 从池获取通道
216
210
  self.channel = await self._get_channel()
217
211
  await self.channel.set_qos(prefetch_count=self.prefetch_count)
218
212
 
@@ -220,7 +214,6 @@ class RabbitMQClient:
220
214
  exchange_exists = await self._check_exchange_exists(self.channel)
221
215
  if not exchange_exists:
222
216
  if self.create_if_not_exists:
223
- # 创建交换机
224
217
  self.exchange = await asyncio.wait_for(
225
218
  self.channel.declare_exchange(
226
219
  name=self.exchange_name,
@@ -235,7 +228,6 @@ class RabbitMQClient:
235
228
  raise Exception(
236
229
  f"交换机 '{self.exchange_name}' 不存在且不允许自动创建")
237
230
  else:
238
- # 获取已有交换机
239
231
  self.exchange = await self.channel.get_exchange(self.exchange_name)
240
232
  logger.info(f"使用已存在的交换机 '{self.exchange_name}'")
241
233
 
@@ -248,7 +240,6 @@ class RabbitMQClient:
248
240
  raise Exception(
249
241
  f"队列 '{self.queue_name}' 不存在且不允许自动创建")
250
242
 
251
- # 创建队列
252
243
  self.queue = await asyncio.wait_for(
253
244
  self.channel.declare_queue(
254
245
  name=self.queue_name,
@@ -261,7 +252,6 @@ class RabbitMQClient:
261
252
  self.actual_queue_name = self.queue_name
262
253
  logger.info(f"已创建队列 '{self.queue_name}'")
263
254
  else:
264
- # 获取已有队列
265
255
  self.queue = await self.channel.get_queue(self.queue_name)
266
256
  self.actual_queue_name = self.queue_name
267
257
  logger.info(f"使用已存在的队列 '{self.queue_name}'")
@@ -272,31 +262,30 @@ class RabbitMQClient:
272
262
  if not bound:
273
263
  raise Exception(f"队列 '{self.queue_name}' 绑定到交换机失败")
274
264
  else:
275
- # 不声明队列时的状态处理
276
265
  self.queue = None
277
266
  self.actual_queue_name = None
278
- logger.debug(f"跳过队列 '{self.queue_name}' 的声明和绑定")
267
+ logger.info(f"跳过队列 '{self.queue_name}' 的声明和绑定")
279
268
 
280
- # 验证连接状态
281
269
  if not self.is_connected:
282
270
  raise Exception("连接验证失败,状态异常")
283
271
 
284
- # 如果之前在消费,重新开始消费
285
- if self._is_consuming and self.message_handler:
272
+ # 重新开始消费(如果之前在消费)
273
+ if self.message_handler:
286
274
  await self.start_consuming()
287
275
 
288
- # 启动连接监控和保活任务
276
+ # 启动监控和保活任务
289
277
  self._start_monitoring()
290
278
  self._start_keepalive()
291
279
 
292
280
  self._update_activity_timestamp()
281
+ # 清理可能残留的跟踪记录
282
+ self._tracking_messages.clear()
293
283
  logger.info(f"RabbitMQ客户端初始化成功 (队列: {self.actual_queue_name})")
294
284
  return
295
285
 
296
286
  except Exception as e:
297
287
  last_exception = e
298
288
  logger.warning(f"资源初始化失败: {str(e)},重试中...")
299
- # 释放当前通道(放回池并重新获取)
300
289
  self.channel = None
301
290
  retries += 1
302
291
  if retries < self.max_reconnection_attempts:
@@ -320,43 +309,54 @@ class RabbitMQClient:
320
309
  await self._recreate_channel()
321
310
  continue
322
311
 
312
+ current_time = asyncio.get_event_loop().time()
313
+ # 清理消息跟踪记录
314
+ if self._tracking_messages:
315
+ # 1. 清理已确认的消息
316
+ acked_ids = [
317
+ msg_id for msg_id, info in self._tracking_messages.items()
318
+ if info.get('acked', False)
319
+ ]
320
+ for msg_id in acked_ids:
321
+ del self._tracking_messages[msg_id]
322
+ if acked_ids:
323
+ logger.info(f"清理了 {len(acked_ids)} 条已确认消息记录")
324
+
323
325
  # 检查消费停滞
324
326
  if self._is_consuming:
325
- current_time = asyncio.get_event_loop().time()
326
327
  if current_time - self._last_message_processed > self.consumption_stall_threshold:
327
- if self._processing_message_ids:
328
+ if self._tracking_messages:
328
329
  logger.warning(
329
- f"消费停滞,但有 {len(self._processing_message_ids)} 个消息正在处理,暂不重启")
330
+ f"消费停滞,但有 {len(self._tracking_messages)} 个消息正在处理,暂不重启")
330
331
  else:
331
- # 确实无消息处理,再重启
332
+ # 无有效消息,重启消费
333
+ logger.info("消费停滞且无消息处理,重启消费")
332
334
  await self.stop_consuming()
333
335
  await asyncio.sleep(1)
334
336
  await self.start_consuming()
337
+
335
338
  except Exception as e:
336
339
  logger.error(f"监控任务出错: {str(e)}")
337
340
  await asyncio.sleep(1)
338
341
 
339
- await asyncio.sleep(30)
342
+ await asyncio.sleep(60)
340
343
 
341
344
  self._monitor_task = asyncio.create_task(monitor())
342
345
 
343
346
  async def _recreate_channel(self) -> None:
344
347
  try:
345
- # 无需手动释放,上下文管理器会自动处理
346
348
  self.channel = await self._get_channel()
347
349
  await self.channel.set_qos(prefetch_count=self.prefetch_count)
348
350
 
349
- # 重新获取交换机
351
+ # 重新获取交换机和队列
350
352
  self.exchange = await self.channel.get_exchange(self.exchange_name)
351
-
352
- # 重新绑定队列
353
353
  if self.queue_name:
354
354
  self.queue = await self.channel.get_queue(self.queue_name)
355
355
  if self.queue and self.exchange:
356
356
  await self._bind_queue(self.channel, self.queue, self.exchange)
357
357
 
358
358
  # 重新开始消费
359
- if self._is_consuming and self.message_handler:
359
+ if self.message_handler:
360
360
  await self.start_consuming()
361
361
 
362
362
  logger.info("通道已重建并恢复服务")
@@ -373,10 +373,9 @@ class RabbitMQClient:
373
373
  async def keepalive():
374
374
  while not self._closed and self.is_connected:
375
375
  current_time = asyncio.get_event_loop().time()
376
- # 检查是否超过指定时间无活动
377
- if current_time - self._last_activity_timestamp > self.connection_pool.heartbeat * 1.5:
378
- logger.debug(
379
- f"连接 {self.connection_pool.heartbeat*1.5}s 无活动,执行保活检查")
376
+ if current_time - self._last_activity_timestamp > self.connection_pool.heartbeat * 2:
377
+ logger.info(
378
+ f"连接 {self.connection_pool.heartbeat*2}s 无活动,执行保活检查")
380
379
  try:
381
380
  if self.channel.is_closed:
382
381
  logger.warning("连接已关闭,触发重连")
@@ -397,7 +396,7 @@ class RabbitMQClient:
397
396
  logger.warning(f"保活检查失败: {str(e)},触发重连")
398
397
  await self.connect(force_reconnect=True)
399
398
 
400
- await asyncio.sleep(self.connection_pool.heartbeat / 2)
399
+ await asyncio.sleep(self.connection_pool.heartbeat)
401
400
 
402
401
  self._keepalive_task = asyncio.create_task(keepalive())
403
402
 
@@ -423,7 +422,7 @@ class RabbitMQClient:
423
422
  async def close(self) -> None:
424
423
  """关闭客户端并释放资源"""
425
424
  self._closed = True
426
- self._is_consuming = False
425
+ self._set_is_consuming(False)
427
426
 
428
427
  # 取消所有任务
429
428
  for task in [self._keepalive_task, self._reconnect_task,
@@ -440,7 +439,7 @@ class RabbitMQClient:
440
439
  self.exchange = None
441
440
  self.queue = None
442
441
  self._consumer_tag = None
443
- self._processing_message_ids.clear()
442
+ self._tracking_messages.clear()
444
443
 
445
444
  logger.info("RabbitMQ客户端已关闭")
446
445
 
@@ -481,24 +480,25 @@ class RabbitMQClient:
481
480
  max_retries = 2
482
481
  while retry_count < max_retries:
483
482
  try:
484
- # 从池获取新通道用于发布(避免长时间占用消费通道)
485
483
  async with self.connection_pool.channel_pool.acquire() as publish_channel:
486
484
  exchange = await publish_channel.get_exchange(self.exchange_name)
487
485
  confirmed = await exchange.publish(
488
486
  message,
489
487
  routing_key=routing_key or self.routing_key or '#',
490
488
  mandatory=True,
491
- timeout=15.0
489
+ timeout=5
492
490
  )
493
491
  if not confirmed:
494
492
  raise Exception("消息未被服务器确认接收")
495
493
 
496
494
  self._update_activity_timestamp()
497
- logger.debug(f"消息已发布到交换机 '{self.exchange_name}'")
495
+ logger.info(f"消息已发布到交换机 '{self.exchange_name}'")
498
496
  return
499
- except (ConnectionClosed, ChannelInvalidStateError):
497
+ except (ConnectionClosed, ChannelInvalidStateError, asyncio.TimeoutError):
498
+ # 覆盖更多异常类型
500
499
  retry_count += 1
501
- logger.warning(f"连接已关闭,尝试重连后重新发布 (重试次数: {retry_count})")
500
+ logger.warning(f"连接异常,尝试重连后重新发布 (重试次数: {retry_count})")
501
+ # 主动刷新连接状态
502
502
  await self.connect(force_reconnect=True)
503
503
  except Exception as e:
504
504
  retry_count += 1
@@ -508,18 +508,16 @@ class RabbitMQClient:
508
508
 
509
509
  raise Exception(f"消息发布失败,经过{retry_count}次重试仍未成功")
510
510
 
511
- # 以下方法(消息消费相关)逻辑与原有保持一致,仅适配连接池
512
511
  def set_message_handler(self, handler):
513
512
  self.message_handler = handler
514
513
 
515
514
  async def start_consuming(self) -> ConsumerTag:
516
515
  if self._is_consuming:
517
- logger.debug("已经在消费中,返回现有consumer_tag")
516
+ logger.info("已经在消费中,返回现有consumer_tag")
518
517
  if self._consumer_tag:
519
518
  return self._consumer_tag
520
- # 如果_is_consuming为True但无consumer_tag,重置状态并重新启动
521
519
  logger.warning("检测到消费状态异常(无consumer_tag),重置状态后重试")
522
- self._is_consuming = False # 重置状态
520
+ self._set_is_consuming(False)
523
521
 
524
522
  if not self.is_connected:
525
523
  await self.connect()
@@ -530,25 +528,21 @@ class RabbitMQClient:
530
528
  if not self.message_handler:
531
529
  raise Exception("未设置消息处理函数")
532
530
 
533
- self._is_consuming = True
534
- logger.info(f"开始消费队列: {self.actual_queue_name}")
535
-
536
531
  try:
537
- # 调用队列的consume方法,确保获取到consumer_tag
538
532
  self._consumer_tag = await self.queue.consume(
539
533
  self._message_wrapper,
540
534
  no_ack=False # 手动确认消息
541
535
  )
542
536
 
543
- # 确保consumer_tag有效
544
537
  if not self._consumer_tag:
545
538
  raise Exception("未能获取到有效的consumer_tag")
546
539
 
540
+ self._set_is_consuming(True)
547
541
  logger.info(
548
542
  f"消费者已启动,队列: {self.actual_queue_name}, tag: {self._consumer_tag}")
549
543
  return self._consumer_tag
550
544
  except Exception as e:
551
- self._is_consuming = False # 异常时重置状态
545
+ self._set_is_consuming(False)
552
546
  logger.error(f"启动消费失败: {str(e)}", exc_info=True)
553
547
  raise
554
548
 
@@ -571,22 +565,25 @@ class RabbitMQClient:
571
565
  if not self._is_consuming:
572
566
  return
573
567
 
574
- self._is_consuming = False
568
+ self._set_is_consuming(False)
575
569
 
576
570
  if self._consumer_tag and self.queue:
577
571
  await self._safe_cancel_consumer()
578
572
 
579
573
  # 等待所有正在处理的消息完成
580
- if self._processing_message_ids:
581
- logger.info(
582
- f"等待 {len(self._processing_message_ids)} 个正在处理的消息完成...")
583
- while self._processing_message_ids and not self._closed:
584
- await asyncio.sleep(0.1)
574
+ if self._tracking_messages:
575
+ logger.info(f"等待 {len(self._tracking_messages)} 个正在处理的消息完成...")
576
+ wait_start = asyncio.get_event_loop().time()
577
+ while self._tracking_messages and not self._closed:
578
+ if asyncio.get_event_loop().time() - wait_start > 30: # 最多等30秒
579
+ logger.warning("等待消息处理超时,强制清理跟踪记录")
580
+ self._tracking_messages.clear()
581
+ break
582
+ await asyncio.sleep(1)
585
583
 
586
584
  # 清理状态
587
585
  self._consumer_tag = None
588
- self._processing_message_ids.clear()
589
-
586
+ self._tracking_messages.clear()
590
587
  logger.info(f"已停止消费队列: {self.actual_queue_name}")
591
588
 
592
589
  async def _parse_message(self, message: AbstractIncomingMessage) -> Union[Dict[str, Any], str]:
@@ -606,8 +603,7 @@ class RabbitMQClient:
606
603
 
607
604
  async def _message_wrapper(self, message: AbstractIncomingMessage) -> None:
608
605
  if not self.message_handler or not self._is_consuming:
609
- logger.warning("未设置消息处理器或已停止消费")
610
- # await message.ack()
606
+ logger.warning("未设置消息处理器或已停止消费,拒绝消息,重新放到队列")
611
607
  try:
612
608
  await message.reject(requeue=True)
613
609
  except Exception as e:
@@ -615,23 +611,31 @@ class RabbitMQClient:
615
611
  return
616
612
 
617
613
  message_id = message.message_id or str(id(message))
618
- if message_id in self._processing_message_ids:
614
+ if message_id in self._tracking_messages:
619
615
  logger.warning(f"检测到重复处理的消息ID: {message_id},直接确认")
620
616
  await message.ack()
621
617
  return
622
618
 
623
- self._processing_message_ids.add(message_id)
619
+ start_time = asyncio.get_event_loop().time()
620
+ self._tracking_messages[message_id] = {
621
+ 'delivery_tag': message.delivery_tag,
622
+ 'acked': False,
623
+ 'channel_number': self.channel.number if self.channel else None,
624
+ 'start_time': start_time
625
+ }
624
626
 
625
627
  try:
626
- logger.debug(f"收到队列 {self.actual_queue_name} 的消息: {message_id}")
628
+ logger.info(f"收到队列 {self.actual_queue_name} 的消息: {message_id}")
629
+ print(f"收到队列 {self.actual_queue_name} 的消息: {message_id}")
627
630
 
628
631
  parsed_data = await self._parse_message(message)
629
632
  await self.message_handler(MQMsgModel(** parsed_data), message)
630
633
 
631
634
  await message.ack()
635
+ self._tracking_messages[message_id]['acked'] = True
632
636
  self._update_activity_timestamp()
633
637
  self._update_message_processed_timestamp()
634
- logger.debug(f"消息 {message_id} 处理完成并确认")
638
+ logger.info(f"消息 {message_id} 处理完成并确认")
635
639
 
636
640
  except Exception as e:
637
641
  current_headers = message.headers or {}
@@ -645,8 +649,9 @@ class RabbitMQClient:
645
649
 
646
650
  if retry_count >= MAX_RETRY_COUNT:
647
651
  logger.error(
648
- f"消息 {message_id} 已达到最大重试次数({MAX_RETRY_COUNT}次),标记为失败")
652
+ f"消息 {message_id} 已达到最大重试次数{MAX_RETRY_COUNT},标记为失败")
649
653
  await message.ack()
654
+ self._tracking_messages[message_id]['acked'] = True
650
655
  self._update_activity_timestamp()
651
656
  return
652
657
 
@@ -661,6 +666,7 @@ class RabbitMQClient:
661
666
  )
662
667
 
663
668
  await message.reject(requeue=False)
669
+ self._tracking_messages[message_id]['acked'] = True
664
670
 
665
671
  if self.exchange:
666
672
  await self.exchange.publish(
@@ -672,8 +678,9 @@ class RabbitMQClient:
672
678
  self._update_activity_timestamp()
673
679
  logger.info(f"消息 {message_id} 已重新发布,当前重试次数: {retry_count}")
674
680
  finally:
675
- if message_id in self._processing_message_ids:
676
- self._processing_message_ids.remove(message_id)
681
+ if message_id in self._tracking_messages:
682
+ del self._tracking_messages[message_id]
683
+ logger.info(f"已删除消息跟踪信息: {message_id}")
677
684
 
678
685
  async def __aenter__(self):
679
686
  await self.connect()
@@ -105,7 +105,7 @@ class RabbitMQService:
105
105
  )
106
106
 
107
107
  # 初始化连接池
108
- await cls._connection_pool.init_pools()
108
+ await asyncio.wait_for(cls._connection_pool.init_pools(), timeout=30)
109
109
  logger.info("RabbitMQ连接池初始化成功")
110
110
 
111
111
  except Exception as e:
@@ -142,7 +142,7 @@ class RabbitMQService:
142
142
  else:
143
143
  logger.info(f"监听器队列已包含app-name: {processed_queue_name}")
144
144
 
145
- logger.debug(
145
+ logger.info(
146
146
  f"创建客户端 - 队列: {processed_queue_name}, 发送器: {is_sender}, "
147
147
  f"允许创建: {create_if_not_exists}"
148
148
  )
@@ -161,7 +161,7 @@ class RabbitMQService:
161
161
  auto_parse_json=kwargs.get('auto_parse_json', True),
162
162
  create_if_not_exists=create_if_not_exists,
163
163
  connection_timeout=kwargs.get('connection_timeout', 10),
164
- rpc_timeout=kwargs.get('rpc_timeout', 5),
164
+ rpc_timeout=kwargs.get('rpc_timeout', 10),
165
165
  reconnection_delay=kwargs.get('reconnection_delay', 1),
166
166
  max_reconnection_attempts=kwargs.get(
167
167
  'max_reconnection_attempts', 5),
@@ -207,12 +207,12 @@ class RabbitMQService:
207
207
  if client.is_connected:
208
208
  # 如果是监听器但队列未初始化,重新连接
209
209
  if not is_sender and not client.queue:
210
- logger.debug(f"客户端 '{client_name}' 队列未初始化,重新连接")
210
+ logger.info(f"客户端 '{client_name}' 队列未初始化,重新连接")
211
211
  client.create_if_not_exists = True
212
212
  await client.connect(force_reconnect=True, declare_queue=True)
213
213
  return client
214
214
  else:
215
- logger.debug(f"客户端 '{client_name}' 连接已关闭,重新连接")
215
+ logger.info(f"客户端 '{client_name}' 连接已关闭,重新连接")
216
216
  if not is_sender:
217
217
  client.create_if_not_exists = True
218
218
  await client.connect(declare_queue=not is_sender)
@@ -240,7 +240,7 @@ class RabbitMQService:
240
240
 
241
241
  # 检查队列是否已初始化
242
242
  if initial_queue_name in cls._initialized_queues:
243
- logger.debug(f"队列 '{initial_queue_name}' 已初始化,直接创建客户端")
243
+ logger.info(f"队列 '{initial_queue_name}' 已初始化,直接创建客户端")
244
244
  client = await cls._create_client(
245
245
  initial_queue_name, ** kwargs
246
246
  )
@@ -296,11 +296,11 @@ class RabbitMQService:
296
296
  normalized_name = queue_name
297
297
  if app_name and normalized_name.endswith(f".{app_name}"):
298
298
  normalized_name = normalized_name[:-len(f".{app_name}")]
299
- logger.debug(f"发送器队列名称移除app-name后缀: {normalized_name}")
299
+ logger.info(f"发送器队列名称移除app-name后缀: {normalized_name}")
300
300
 
301
301
  # 检查是否已初始化
302
302
  if normalized_name in cls._sender_client_names:
303
- logger.debug(f"发送客户端 '{normalized_name}' 已存在,跳过")
303
+ logger.info(f"发送客户端 '{normalized_name}' 已存在,跳过")
304
304
  continue
305
305
 
306
306
  # 获取或创建客户端
@@ -405,7 +405,7 @@ class RabbitMQService:
405
405
  raise ValueError("RabbitMQService尚未初始化,请先调用init方法")
406
406
 
407
407
  if queue_name in cls._message_handlers:
408
- logger.debug(f"监听器 '{queue_name}' 已存在,跳过重复添加")
408
+ logger.info(f"监听器 '{queue_name}' 已存在,跳过重复添加")
409
409
  return
410
410
 
411
411
  # 创建并初始化客户端
@@ -429,7 +429,7 @@ class RabbitMQService:
429
429
  async def start_consumer(cls, client_name: str) -> None:
430
430
  """启动指定客户端的消费者"""
431
431
  if client_name in cls._consumer_tasks and not cls._consumer_tasks[client_name].done():
432
- logger.debug(f"消费者 '{client_name}' 已在运行中,无需重复启动")
432
+ logger.info(f"消费者 '{client_name}' 已在运行中,无需重复启动")
433
433
  return
434
434
 
435
435
  if client_name not in cls._clients:
@@ -451,7 +451,7 @@ class RabbitMQService:
451
451
  if asyncio.get_event_loop().time() - start_time > cls.CONSUMER_START_TIMEOUT:
452
452
  raise TimeoutError(f"等待客户端 '{client_name}' 连接超时")
453
453
 
454
- logger.debug(f"等待客户端 '{client_name}' 连接就绪...")
454
+ logger.info(f"等待客户端 '{client_name}' 连接就绪...")
455
455
  await asyncio.sleep(1)
456
456
 
457
457
  # 创建停止事件
@@ -557,7 +557,7 @@ class RabbitMQService:
557
557
  if app_name and f"{queue_name}.{app_name}" in cls._sender_client_names:
558
558
  return cls._clients.get(f"{queue_name}.{app_name}")
559
559
 
560
- logger.debug(f"未找到发送器 '{queue_name}'")
560
+ logger.info(f"未找到发送器 '{queue_name}'")
561
561
  return None
562
562
 
563
563
  @classmethod
@@ -651,7 +651,7 @@ class RabbitMQService:
651
651
  raise
652
652
 
653
653
  @classmethod
654
- async def shutdown(cls, timeout: float = 10.0) -> None:
654
+ async def shutdown(cls, timeout: float = 15.0) -> None:
655
655
  """优雅关闭所有资源(新增连接池关闭逻辑)"""
656
656
  start_time = asyncio.get_event_loop().time()
657
657
  logger.info("开始关闭RabbitMQ服务...")
@@ -199,6 +199,10 @@ class Services(metaclass=SingletonMeta):
199
199
  if not sender:
200
200
  raise ValueError(f"发送器 '{queue_name}' 不存在")
201
201
 
202
+ if not (sender.is_connected and sender.channel and not sender.channel.is_closed):
203
+ logging.info(f"发送器 '{queue_name}' 连接无效,强制重连")
204
+ await sender.connect(force_reconnect=True, declare_queue=False)
205
+
202
206
  await RabbitMQService.send_message(data, queue_name, ** kwargs)
203
207
  logging.info(f"消息发送成功(尝试 {attempt+1}/{max_retries})")
204
208
  return
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sycommon-python-lib
3
- Version: 0.1.31
3
+ Version: 0.1.33
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown