sycommon-python-lib 0.1.46__py3-none-any.whl → 0.1.56b5__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.
Files changed (30) hide show
  1. sycommon/config/Config.py +6 -2
  2. sycommon/config/RerankerConfig.py +1 -0
  3. sycommon/database/async_base_db_service.py +36 -0
  4. sycommon/database/async_database_service.py +96 -0
  5. sycommon/llm/__init__.py +0 -0
  6. sycommon/llm/embedding.py +149 -0
  7. sycommon/llm/get_llm.py +246 -0
  8. sycommon/llm/llm_logger.py +126 -0
  9. sycommon/llm/llm_tokens.py +119 -0
  10. sycommon/logging/async_sql_logger.py +65 -0
  11. sycommon/logging/kafka_log.py +21 -9
  12. sycommon/logging/logger_levels.py +23 -0
  13. sycommon/middleware/context.py +2 -0
  14. sycommon/middleware/traceid.py +155 -32
  15. sycommon/notice/__init__.py +0 -0
  16. sycommon/notice/uvicorn_monitor.py +195 -0
  17. sycommon/rabbitmq/rabbitmq_client.py +144 -152
  18. sycommon/rabbitmq/rabbitmq_pool.py +213 -479
  19. sycommon/rabbitmq/rabbitmq_service.py +77 -127
  20. sycommon/services.py +78 -75
  21. sycommon/synacos/feign.py +18 -7
  22. sycommon/synacos/feign_client.py +26 -8
  23. sycommon/synacos/nacos_service.py +18 -2
  24. sycommon/tools/merge_headers.py +97 -0
  25. sycommon/tools/snowflake.py +290 -23
  26. {sycommon_python_lib-0.1.46.dist-info → sycommon_python_lib-0.1.56b5.dist-info}/METADATA +15 -10
  27. {sycommon_python_lib-0.1.46.dist-info → sycommon_python_lib-0.1.56b5.dist-info}/RECORD +30 -18
  28. {sycommon_python_lib-0.1.46.dist-info → sycommon_python_lib-0.1.56b5.dist-info}/WHEEL +0 -0
  29. {sycommon_python_lib-0.1.46.dist-info → sycommon_python_lib-0.1.56b5.dist-info}/entry_points.txt +0 -0
  30. {sycommon_python_lib-0.1.46.dist-info → sycommon_python_lib-0.1.56b5.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  import asyncio
2
2
  import json
3
3
  from typing import (
4
- Callable, Coroutine, Dict, List, Optional, Type, Union, Any, Set
4
+ Callable, Coroutine, Dict, List, Optional, Type, Union, Any
5
5
  )
6
6
  from pydantic import BaseModel
7
7
  from aio_pika.abc import AbstractIncomingMessage, ConsumerTag
@@ -18,11 +18,11 @@ logger = SYLogger
18
18
 
19
19
  class RabbitMQService:
20
20
  """
21
- RabbitMQ服务封装,管理多个客户端实例,基于连接池实现资源复用
22
- 适配细粒度锁设计的RabbitMQClient,确保线程安全+高可用
21
+ RabbitMQ服务封装,管理多个客户端实例(适配单通道连接池)
22
+ 核心特性:基于单通道连接池复用资源,简化状态管理,依赖原生自动重连
23
23
  """
24
24
 
25
- # 保存多个客户端实例
25
+ # 保存多个客户端实例(共享单通道,仅维护配置差异)
26
26
  _clients: Dict[str, RabbitMQClient] = {}
27
27
  # 保存消息处理器
28
28
  _message_handlers: Dict[str, Callable[[
@@ -37,8 +37,6 @@ class RabbitMQService:
37
37
  _consumer_events: Dict[str, asyncio.Event] = {}
38
38
  # 存储消费者标签
39
39
  _consumer_tags: Dict[str, ConsumerTag] = {}
40
- # 跟踪已初始化的队列
41
- _initialized_queues: Set[str] = set()
42
40
  # 异步锁,确保初始化安全
43
41
  _init_locks: Dict[str, asyncio.Lock] = {}
44
42
  # 标记是否有监听器和发送器
@@ -46,7 +44,7 @@ class RabbitMQService:
46
44
  _has_senders: bool = False
47
45
  # 消费启动超时设置
48
46
  CONSUMER_START_TIMEOUT = 30 # 30秒超时
49
- # 连接池实例
47
+ # 连接池实例(单通道)
50
48
  _connection_pool: Optional[RabbitMQConnectionPool] = None
51
49
  # 服务关闭标记
52
50
  _is_shutdown: bool = False
@@ -56,11 +54,10 @@ class RabbitMQService:
56
54
  _connection_monitor_task: Optional[asyncio.Task] = None
57
55
  # 重连配置
58
56
  RECONNECT_INTERVAL = 15 # 重连基础间隔(秒)
59
- MAX_RECONNECT_ATTEMPTS = 10 # 最大连续重连次数
60
57
 
61
58
  @classmethod
62
59
  def init(cls, config: dict, has_listeners: bool = False, has_senders: bool = False) -> Type['RabbitMQService']:
63
- """初始化RabbitMQ服务(支持集群配置),同时创建连接池"""
60
+ """初始化RabbitMQ服务(支持集群配置),同时创建单通道连接池"""
64
61
  from sycommon.synacos.nacos_service import NacosService
65
62
 
66
63
  # 防止重复初始化
@@ -98,7 +95,7 @@ class RabbitMQService:
98
95
 
99
96
  @classmethod
100
97
  async def _init_connection_pool(cls):
101
- """初始化连接池(异步操作,带重试)"""
98
+ """初始化单通道连接池(异步操作,带重试)"""
102
99
  if cls._connection_pool or not cls._config or cls._is_shutdown:
103
100
  return
104
101
 
@@ -112,7 +109,7 @@ class RabbitMQService:
112
109
 
113
110
  global_prefetch_count = cls._config.get('prefetch_count', 2)
114
111
 
115
- # 创建连接池
112
+ # 创建单通道连接池(已移除channel_pool_size参数)
116
113
  cls._connection_pool = RabbitMQConnectionPool(
117
114
  hosts=hosts_list,
118
115
  port=cls._config.get('port', 5672),
@@ -121,11 +118,14 @@ class RabbitMQService:
121
118
  virtualhost=cls._config.get('virtual-host', "/"),
122
119
  app_name=cls._config.get("APP_NAME", ""),
123
120
  prefetch_count=global_prefetch_count,
121
+ heartbeat=cls._config.get('heartbeat', 30),
122
+ connection_timeout=cls._config.get('connection_timeout', 30),
123
+ reconnect_interval=cls._config.get('reconnect_interval', 5),
124
124
  )
125
125
 
126
126
  # 初始化连接池
127
127
  await asyncio.wait_for(cls._connection_pool.init_pools(), timeout=30)
128
- logger.info("RabbitMQ连接池初始化成功")
128
+ logger.info("RabbitMQ单通道连接池初始化成功")
129
129
 
130
130
  except Exception as e:
131
131
  logger.error(f"RabbitMQ连接池初始化失败: {str(e)}", exc_info=True)
@@ -136,7 +136,7 @@ class RabbitMQService:
136
136
 
137
137
  @classmethod
138
138
  async def _monitor_connections(cls):
139
- """连接监控任务:定期检查所有客户端连接状态,自动重连"""
139
+ """连接监控任务:定期检查所有客户端连接状态,依赖连接池原生重连"""
140
140
  logger.info("RabbitMQ连接监控任务启动")
141
141
  while not cls._is_shutdown:
142
142
  try:
@@ -146,40 +146,25 @@ class RabbitMQService:
146
146
  if not cls._connection_pool or not cls._connection_pool._initialized:
147
147
  continue
148
148
 
149
- # 检查所有客户端连接
150
- # 使用list避免迭代中修改
149
+ # 检查连接池本身状态
150
+ pool_alive = await cls._connection_pool.is_alive
151
+ if not pool_alive:
152
+ logger.error("RabbitMQ连接池已断开,等待原生自动重连")
153
+ continue
154
+
155
+ # 检查所有客户端连接(单通道场景下,客户端状态依赖通道有效性)
151
156
  for client_name, client in list(cls._clients.items()):
152
157
  try:
153
- # 双重校验连接状态(客户端内部校验 + 连接池连接校验)
154
158
  client_connected = await client.is_connected
155
- conn_connected = not (
156
- client._channel_conn and client._channel_conn.is_closed)
157
-
158
- if not client_connected or not conn_connected:
159
+ if not client_connected:
159
160
  logger.warning(
160
- f"客户端 '{client_name}' 连接异常 - 客户端状态: {client_connected}, "
161
- f"连接状态: {conn_connected},触发自动重连"
162
- )
163
-
164
- # 重连前先清理无效资源
165
- await cls._clean_client_resources(client)
166
-
167
- # 执行重连(带重试)
168
- reconnect_success = await cls._reconnect_client(client_name, client)
169
- if reconnect_success:
170
- logger.info(f"客户端 '{client_name}' 重连成功")
171
- else:
172
- logger.error(f"客户端 '{client_name}' 重连失败,将继续监控")
173
-
161
+ f"客户端 '{client_name}' 连接异常,触发重连")
162
+ asyncio.create_task(
163
+ cls._reconnect_client(client_name, client))
174
164
  except Exception as e:
175
165
  logger.error(
176
166
  f"监控客户端 '{client_name}' 连接状态失败: {str(e)}", exc_info=True)
177
167
 
178
- # 检查连接池状态(如果连接池已关闭,重新初始化)
179
- if not await cls._connection_pool.is_alive:
180
- logger.error("RabbitMQ连接池已关闭,尝试重新初始化")
181
- asyncio.create_task(cls._init_connection_pool())
182
-
183
168
  except Exception as e:
184
169
  logger.error("RabbitMQ连接监控任务异常", exc_info=True)
185
170
  await asyncio.sleep(cls.RECONNECT_INTERVAL) # 异常后延迟重启监控
@@ -188,19 +173,16 @@ class RabbitMQService:
188
173
 
189
174
  @classmethod
190
175
  async def _clean_client_resources(cls, client: RabbitMQClient):
191
- """清理客户端无效资源(通道+连接)"""
176
+ """清理客户端无效资源(单通道场景下仅重置状态,无需归还通道)"""
192
177
  try:
193
- if client._channel and client._channel_conn:
194
- # 先停止消费(避免消费中释放资源)
195
- if client._consumer_tag:
196
- await client.stop_consuming()
197
- # 释放通道到连接池
198
- await cls._connection_pool.release_channel(client._channel, client._channel_conn)
199
- logger.debug("客户端无效资源释放成功")
178
+ # 先停止消费(避免消费中操作资源)
179
+ if client._consumer_tag:
180
+ await client.stop_consuming()
181
+ logger.debug("客户端无效资源清理完成(单通道无需归还)")
200
182
  except Exception as e:
201
183
  logger.warning(f"释放客户端无效资源失败: {str(e)}")
202
184
  finally:
203
- # 强制重置客户端状态
185
+ # 强制重置客户端状态(通道由连接池自动恢复)
204
186
  client._channel = None
205
187
  client._channel_conn = None
206
188
  client._exchange = None
@@ -209,48 +191,38 @@ class RabbitMQService:
209
191
 
210
192
  @classmethod
211
193
  async def _reconnect_client(cls, client_name: str, client: RabbitMQClient) -> bool:
212
- """客户端重连(带重试机制)"""
213
- # 重连冷却,避免任务堆积
214
- cooldown = cls.RECONNECT_INTERVAL * 2
215
- await asyncio.sleep(cooldown)
194
+ """客户端重连(依赖连接池原生重连,仅重建客户端资源)"""
195
+ if cls._is_shutdown or not await cls._connection_pool.is_alive:
196
+ return False
216
197
 
217
- for attempt in range(cls.MAX_RECONNECT_ATTEMPTS):
218
- try:
219
- # 执行重连
220
- await client.connect()
198
+ # 重连冷却
199
+ await asyncio.sleep(cls.RECONNECT_INTERVAL)
221
200
 
222
- # 验证重连结果(双重校验)
223
- if await client.is_connected and client._queue:
224
- # 如果是消费者,重新启动消费
225
- if client_name in cls._message_handlers:
226
- # 先停止旧的消费任务
227
- if client_name in cls._consumer_tasks:
228
- old_task = cls._consumer_tasks[client_name]
229
- if not old_task.done():
230
- old_task.cancel()
231
- try:
232
- await asyncio.wait_for(old_task, timeout=5)
233
- except:
234
- pass
235
- # 启动新的消费任务
236
- await cls.start_consumer(client_name)
237
- return True
238
- else:
239
- logger.warning(
240
- f"客户端 '{client_name}' 重连尝试 {attempt+1} 失败:资源未完全初始化")
241
- except Exception as e:
242
- logger.error(
243
- f"客户端 '{client_name}' 重连尝试 {attempt+1} 失败: {str(e)}", exc_info=True)
201
+ try:
202
+ # 清理旧资源
203
+ await cls._clean_client_resources(client)
244
204
 
245
- await asyncio.sleep(cls.RECONNECT_INTERVAL)
205
+ # 执行重连(客户端内部会从连接池获取新通道)
206
+ await client.connect()
246
207
 
247
- if not cls._is_shutdown:
248
- asyncio.create_task(cls._reconnect_client(client_name, client))
249
- return False
208
+ # 验证重连结果
209
+ if await client.is_connected:
210
+ logger.info(f"客户端 '{client_name}' 重连成功")
211
+ # 如果是消费者,重新启动消费
212
+ if client_name in cls._message_handlers:
213
+ await cls.start_consumer(client_name)
214
+ return True
215
+ else:
216
+ logger.warning(f"客户端 '{client_name}' 重连失败:资源未完全初始化")
217
+ return False
218
+ except Exception as e:
219
+ logger.error(f"客户端 '{client_name}' 重连失败: {str(e)}", exc_info=True)
220
+ # 重连失败后,由监控任务再次触发(避免死循环)
221
+ return False
250
222
 
251
223
  @classmethod
252
224
  async def _create_client(cls, queue_name: str, **kwargs) -> RabbitMQClient:
253
- """创建客户端实例(适配新的RabbitMQClient API)"""
225
+ """创建客户端实例(适配单通道连接池的RabbitMQClient)"""
254
226
  if cls._is_shutdown:
255
227
  raise RuntimeError("RabbitMQService已关闭,无法创建客户端")
256
228
 
@@ -285,7 +257,7 @@ class RabbitMQService:
285
257
  f"允许创建: {create_if_not_exists}"
286
258
  )
287
259
 
288
- # 创建客户端实例(适配新的RabbitMQClient参数)
260
+ # 创建客户端实例(适配精简版RabbitMQClient参数)
289
261
  client = RabbitMQClient(
290
262
  connection_pool=cls._connection_pool,
291
263
  exchange_name=cls._config.get(
@@ -301,15 +273,9 @@ class RabbitMQService:
301
273
  prefetch_count=kwargs.get('prefetch_count', 2),
302
274
  )
303
275
 
304
- # 连接客户端
276
+ # 连接客户端(单通道场景下快速连接)
305
277
  await client.connect()
306
278
 
307
- # 监听器客户端连接后延迟1秒,确保消费状态就绪(仅首次启动)
308
- if not is_sender and create_if_not_exists:
309
- logger.info(
310
- f"监听器客户端 '{processed_queue_name}' 连接成功,延迟1秒启动消费(解决启动时序问题)")
311
- await asyncio.sleep(1)
312
-
313
279
  return client
314
280
 
315
281
  @classmethod
@@ -317,7 +283,7 @@ class RabbitMQService:
317
283
  cls,
318
284
  client_name: str = "default", **kwargs
319
285
  ) -> RabbitMQClient:
320
- """获取或创建RabbitMQ客户端(基于连接池,线程安全)"""
286
+ """获取或创建RabbitMQ客户端(单通道池,线程安全)"""
321
287
  if cls._is_shutdown:
322
288
  raise RuntimeError("RabbitMQService已关闭,无法获取客户端")
323
289
 
@@ -353,7 +319,7 @@ class RabbitMQService:
353
319
  await client.connect()
354
320
  return client
355
321
  else:
356
- logger.info(f"客户端 '{client_name}' 连接已关闭,重新连接")
322
+ logger.info(f"客户端 '{client_name}' 连接已断开,重新连接")
357
323
  if not is_sender:
358
324
  client.create_if_not_exists = True
359
325
  await client.connect()
@@ -375,16 +341,9 @@ class RabbitMQService:
375
341
  cls._clients[client_name] = client
376
342
  return client
377
343
 
378
- # 监听器逻辑
344
+ # 监听器逻辑(单通道支持多队列声明,无需跟踪已初始化队列)
379
345
  kwargs['create_if_not_exists'] = True
380
346
 
381
- # 检查队列是否已初始化
382
- if initial_queue_name in cls._initialized_queues:
383
- logger.info(f"队列 '{initial_queue_name}' 已初始化,直接创建客户端")
384
- client = await cls._create_client(initial_queue_name, **kwargs)
385
- cls._clients[client_name] = client
386
- return client
387
-
388
347
  # 创建并连接客户端
389
348
  client = await cls._create_client(
390
349
  initial_queue_name,
@@ -400,17 +359,12 @@ class RabbitMQService:
400
359
  if not client._queue:
401
360
  raise Exception(f"无法创建队列 '{initial_queue_name}'")
402
361
 
403
- # 记录已初始化的队列
404
- final_queue_name = client.queue_name
405
- if final_queue_name:
406
- cls._initialized_queues.add(final_queue_name)
407
-
408
362
  cls._clients[client_name] = client
409
363
  return client
410
364
 
411
365
  @classmethod
412
366
  async def setup_senders(cls, senders: List[RabbitMQSendConfig], has_listeners: bool = False, **kwargs) -> None:
413
- """设置消息发送器(适配新客户端)"""
367
+ """设置消息发送器(适配单通道客户端)"""
414
368
  if cls._is_shutdown:
415
369
  logger.warning("服务已关闭,无法设置发送器")
416
370
  return
@@ -475,7 +429,7 @@ class RabbitMQService:
475
429
 
476
430
  @classmethod
477
431
  async def setup_listeners(cls, listeners: List[RabbitMQListenerConfig], has_senders: bool = False, **kwargs) -> None:
478
- """设置消息监听器(适配新客户端)"""
432
+ """设置消息监听器(适配单通道客户端)"""
479
433
  if cls._is_shutdown:
480
434
  logger.warning("服务已关闭,无法设置监听器")
481
435
  return
@@ -544,7 +498,7 @@ class RabbitMQService:
544
498
  queue_name: str,
545
499
  handler: Callable[[MQMsgModel, AbstractIncomingMessage], Coroutine[Any, Any, None]], **kwargs
546
500
  ) -> None:
547
- """添加消息监听器(线程安全)"""
501
+ """添加消息监听器(线程安全,单通道场景)"""
548
502
  if cls._is_shutdown:
549
503
  logger.warning("服务已关闭,无法添加监听器")
550
504
  return
@@ -569,7 +523,7 @@ class RabbitMQService:
569
523
 
570
524
  @classmethod
571
525
  async def start_all_consumers(cls) -> None:
572
- """启动所有已注册的消费者(线程安全)"""
526
+ """启动所有已注册的消费者(单通道场景,避免阻塞)"""
573
527
  if cls._is_shutdown:
574
528
  logger.warning("服务已关闭,无法启动消费者")
575
529
  return
@@ -579,7 +533,7 @@ class RabbitMQService:
579
533
 
580
534
  @classmethod
581
535
  async def start_consumer(cls, client_name: str) -> None:
582
- """启动指定客户端的消费者"""
536
+ """启动指定客户端的消费者(单通道消费,需确保回调非阻塞)"""
583
537
  if cls._is_shutdown:
584
538
  logger.warning("服务已关闭,无法启动消费者")
585
539
  return
@@ -622,20 +576,15 @@ class RabbitMQService:
622
576
  if cls._is_shutdown:
623
577
  return
624
578
 
625
- # 监听器启动消费前额外延迟1秒
626
- if cls._has_listeners and not client_name.startswith("sender-"):
627
- logger.info(f"消费者 '{client_name}' 准备启动,延迟1秒等待消费状态就绪")
628
- await asyncio.sleep(1)
629
-
630
579
  # 创建停止事件
631
580
  stop_event = asyncio.Event()
632
581
  cls._consumer_events[client_name] = stop_event
633
582
 
634
- # 定义消费任务
583
+ # 定义消费任务(单通道场景下,消费回调需非阻塞)
635
584
  async def consume_task():
636
585
  try:
637
586
  # 启动消费,带重试机制
638
- max_attempts = 5
587
+ max_attempts = 3
639
588
  attempt = 0
640
589
  consumer_tag = None
641
590
 
@@ -671,7 +620,9 @@ class RabbitMQService:
671
620
  # 记录消费者标签
672
621
  cls._consumer_tags[client_name] = consumer_tag
673
622
  logger.info(
674
- f"消费者 '{client_name}' 开始消费,tag: {consumer_tag}")
623
+ f"消费者 '{client_name}' 开始消费(单通道),tag: {consumer_tag}"
624
+ f"注意:消费回调需非阻塞,避免影响其他客户端"
625
+ )
675
626
 
676
627
  # 等待停止事件
677
628
  await stop_event.wait()
@@ -731,7 +682,7 @@ class RabbitMQService:
731
682
 
732
683
  @classmethod
733
684
  async def get_sender(cls, queue_name: str) -> Optional[RabbitMQClient]:
734
- """获取发送客户端"""
685
+ """获取发送客户端(适配单通道池)"""
735
686
  if cls._is_shutdown:
736
687
  logger.warning("服务已关闭,无法获取发送器")
737
688
  return None
@@ -781,7 +732,7 @@ class RabbitMQService:
781
732
  data: Union[BaseModel, str, Dict[str, Any], None],
782
733
  queue_name: str, **kwargs
783
734
  ) -> None:
784
- """发送消息到指定队列"""
735
+ """发送消息到指定队列(单通道场景下快速发送)"""
785
736
  if cls._is_shutdown:
786
737
  raise RuntimeError("RabbitMQService已关闭,无法发送消息")
787
738
 
@@ -853,7 +804,7 @@ class RabbitMQService:
853
804
  ).model_dump_json()
854
805
  }
855
806
 
856
- # 发送消息
807
+ # 发送消息(单通道场景下依赖原生异步确认)
857
808
  await sender.publish(
858
809
  message_body=mq_message.model_dump_json(),
859
810
  headers=mq_header,
@@ -866,7 +817,7 @@ class RabbitMQService:
866
817
 
867
818
  @classmethod
868
819
  async def shutdown(cls, timeout: float = 15.0) -> None:
869
- """优雅关闭所有资源(线程安全)"""
820
+ """优雅关闭所有资源(单通道场景下简化关闭流程)"""
870
821
  async with cls._shutdown_lock:
871
822
  if cls._is_shutdown:
872
823
  logger.info("RabbitMQService已关闭,无需重复操作")
@@ -898,18 +849,18 @@ class RabbitMQService:
898
849
  except Exception as e:
899
850
  logger.error(f"关闭消费者 '{client_name}' 失败: {str(e)}")
900
851
 
901
- # 3. 关闭所有客户端
852
+ # 3. 关闭所有客户端(单通道场景下客户端关闭仅清理状态)
902
853
  for client in cls._clients.values():
903
854
  try:
904
855
  await client.close()
905
856
  except Exception as e:
906
857
  logger.error(f"关闭客户端失败: {str(e)}")
907
858
 
908
- # 4. 关闭连接池
859
+ # 4. 关闭连接池(单通道池关闭会释放所有资源)
909
860
  if cls._connection_pool and cls._connection_pool._initialized:
910
861
  try:
911
862
  await cls._connection_pool.close()
912
- logger.info("RabbitMQ连接池已关闭")
863
+ logger.info("RabbitMQ单通道连接池已关闭")
913
864
  except Exception as e:
914
865
  logger.error(f"关闭连接池失败: {str(e)}")
915
866
 
@@ -919,7 +870,6 @@ class RabbitMQService:
919
870
  cls._consumer_tasks.clear()
920
871
  cls._consumer_events.clear()
921
872
  cls._consumer_tags.clear()
922
- cls._initialized_queues.clear()
923
873
  cls._sender_client_names.clear()
924
874
  cls._init_locks.clear()
925
875
  cls._config = None