sycommon-python-lib 0.1.56__py3-none-any.whl → 0.1.56b2__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 (40) hide show
  1. sycommon/config/Config.py +3 -24
  2. sycommon/llm/embedding.py +23 -78
  3. sycommon/llm/get_llm.py +164 -24
  4. sycommon/logging/kafka_log.py +433 -187
  5. sycommon/middleware/exception.py +16 -10
  6. sycommon/middleware/timeout.py +1 -2
  7. sycommon/middleware/traceid.py +76 -81
  8. sycommon/rabbitmq/rabbitmq_client.py +242 -232
  9. sycommon/rabbitmq/rabbitmq_pool.py +218 -278
  10. sycommon/rabbitmq/rabbitmq_service.py +843 -25
  11. sycommon/services.py +96 -122
  12. sycommon/synacos/nacos_service.py +779 -63
  13. sycommon/tools/merge_headers.py +0 -20
  14. sycommon/tools/snowflake.py +153 -101
  15. {sycommon_python_lib-0.1.56.dist-info → sycommon_python_lib-0.1.56b2.dist-info}/METADATA +8 -10
  16. {sycommon_python_lib-0.1.56.dist-info → sycommon_python_lib-0.1.56b2.dist-info}/RECORD +19 -40
  17. sycommon/config/LangfuseConfig.py +0 -15
  18. sycommon/config/SentryConfig.py +0 -13
  19. sycommon/llm/llm_tokens.py +0 -119
  20. sycommon/llm/struct_token.py +0 -192
  21. sycommon/llm/sy_langfuse.py +0 -103
  22. sycommon/llm/usage_token.py +0 -117
  23. sycommon/notice/__init__.py +0 -0
  24. sycommon/notice/uvicorn_monitor.py +0 -200
  25. sycommon/rabbitmq/rabbitmq_service_client_manager.py +0 -206
  26. sycommon/rabbitmq/rabbitmq_service_connection_monitor.py +0 -73
  27. sycommon/rabbitmq/rabbitmq_service_consumer_manager.py +0 -285
  28. sycommon/rabbitmq/rabbitmq_service_core.py +0 -117
  29. sycommon/rabbitmq/rabbitmq_service_producer_manager.py +0 -238
  30. sycommon/sentry/__init__.py +0 -0
  31. sycommon/sentry/sy_sentry.py +0 -35
  32. sycommon/synacos/nacos_client_base.py +0 -119
  33. sycommon/synacos/nacos_config_manager.py +0 -107
  34. sycommon/synacos/nacos_heartbeat_manager.py +0 -144
  35. sycommon/synacos/nacos_service_discovery.py +0 -157
  36. sycommon/synacos/nacos_service_registration.py +0 -270
  37. sycommon/tools/env.py +0 -62
  38. {sycommon_python_lib-0.1.56.dist-info → sycommon_python_lib-0.1.56b2.dist-info}/WHEEL +0 -0
  39. {sycommon_python_lib-0.1.56.dist-info → sycommon_python_lib-0.1.56b2.dist-info}/entry_points.txt +0 -0
  40. {sycommon_python_lib-0.1.56.dist-info → sycommon_python_lib-0.1.56b2.dist-info}/top_level.txt +0 -0
@@ -1,285 +0,0 @@
1
- from typing import Dict, List, Callable, Coroutine, Any
2
- import asyncio
3
- from aio_pika.abc import AbstractIncomingMessage, ConsumerTag
4
-
5
- from sycommon.logging.kafka_log import SYLogger
6
- from sycommon.models.mqlistener_config import RabbitMQListenerConfig
7
- from sycommon.rabbitmq.rabbitmq_service_client_manager import RabbitMQClientManager
8
- from sycommon.models.mqmsg_model import MQMsgModel
9
-
10
- logger = SYLogger
11
-
12
-
13
- class RabbitMQConsumerManager(RabbitMQClientManager):
14
- """
15
- RabbitMQ消费者管理类 - 负责监听器设置、消费启动/停止、消费验证
16
- """
17
- # 消费者相关状态
18
- _message_handlers: Dict[str, Callable[[
19
- MQMsgModel, AbstractIncomingMessage], Coroutine[Any, Any, None]]] = {}
20
- _consumer_tasks: Dict[str, asyncio.Task] = {}
21
- _consumer_events: Dict[str, asyncio.Event] = {}
22
- _consumer_tags: Dict[str, ConsumerTag] = {}
23
-
24
- # 配置常量
25
- CONSUMER_START_TIMEOUT = 30 # 消费启动超时(秒)
26
-
27
- @classmethod
28
- async def add_listener(
29
- cls,
30
- queue_name: str,
31
- handler: Callable[[MQMsgModel, AbstractIncomingMessage], Coroutine[Any, Any, None]], **kwargs
32
- ) -> None:
33
- """添加消息监听器"""
34
- if cls._is_shutdown:
35
- logger.warning("服务已关闭,无法添加监听器")
36
- return
37
-
38
- if queue_name in cls._message_handlers:
39
- logger.info(f"监听器 '{queue_name}' 已存在,跳过重复添加")
40
- return
41
-
42
- # 创建并初始化客户端
43
- await cls.get_client(
44
- client_name=queue_name,
45
- client_type="listener",
46
- queue_name=queue_name,
47
- ** kwargs
48
- )
49
-
50
- # 注册消息处理器
51
- cls._message_handlers[queue_name] = handler
52
- logger.info(f"监听器 '{queue_name}' 已添加")
53
-
54
- @classmethod
55
- async def setup_listeners(cls, listeners: List[RabbitMQListenerConfig], has_senders: bool = False, **kwargs) -> None:
56
- """设置消息监听器"""
57
- if cls._is_shutdown:
58
- logger.warning("服务已关闭,无法设置监听器")
59
- return
60
-
61
- cls.set_mode_flags(has_listeners=True, has_senders=has_senders)
62
- logger.info(f"开始设置 {len(listeners)} 个消息监听器")
63
-
64
- for idx, listener_config in enumerate(listeners):
65
- try:
66
- # 转换配置
67
- listener_dict = listener_config.model_dump()
68
- listener_dict['create_if_not_exists'] = True
69
- listener_dict['prefetch_count'] = listener_config.prefetch_count
70
- queue_name = listener_dict['queue_name']
71
-
72
- logger.info(
73
- f"设置监听器 {idx+1}/{len(listeners)}: {queue_name} (prefetch_count: {listener_config.prefetch_count})")
74
-
75
- # 添加监听器
76
- await cls.add_listener(**listener_dict)
77
- except Exception as e:
78
- logger.error(
79
- f"设置监听器 {idx+1} 失败: {str(e)}", exc_info=True)
80
- logger.warning("继续处理其他监听器")
81
-
82
- # 启动所有消费者
83
- await cls.start_all_consumers()
84
-
85
- # 验证消费者启动结果
86
- await cls._verify_consumers_started()
87
-
88
- logger.info(f"消息监听器设置完成")
89
-
90
- @classmethod
91
- async def _verify_consumers_started(cls, timeout: int = 30) -> None:
92
- """验证消费者是否成功启动"""
93
- start_time = asyncio.get_event_loop().time()
94
- required_clients = list(cls._message_handlers.keys())
95
- running_clients = []
96
-
97
- while len(running_clients) < len(required_clients) and \
98
- (asyncio.get_event_loop().time() - start_time) < timeout and \
99
- not cls._is_shutdown:
100
-
101
- running_clients = [
102
- name for name, task in cls._consumer_tasks.items()
103
- if not task.done() and name in cls._consumer_tags
104
- ]
105
-
106
- logger.info(
107
- f"消费者启动验证: {len(running_clients)}/{len(required_clients)} 已启动")
108
- await asyncio.sleep(1)
109
-
110
- failed_clients = [
111
- name for name in required_clients if name not in running_clients and not cls._is_shutdown]
112
- if failed_clients:
113
- logger.error(f"以下消费者启动失败: {', '.join(failed_clients)}")
114
- for client_name in failed_clients:
115
- logger.info(f"尝试重新启动消费者: {client_name}")
116
- asyncio.create_task(cls.start_consumer(client_name))
117
-
118
- @classmethod
119
- async def start_all_consumers(cls) -> None:
120
- """启动所有已注册的消费者"""
121
- if cls._is_shutdown:
122
- logger.warning("服务已关闭,无法启动消费者")
123
- return
124
-
125
- for client_name in cls._message_handlers:
126
- await cls.start_consumer(client_name)
127
-
128
- @classmethod
129
- async def start_consumer(cls, client_name: str) -> None:
130
- """启动指定客户端的消费者"""
131
- if cls._is_shutdown:
132
- logger.warning("服务已关闭,无法启动消费者")
133
- return
134
-
135
- # 检查任务状态
136
- if client_name in cls._consumer_tasks:
137
- existing_task = cls._consumer_tasks[client_name]
138
- if not existing_task.done():
139
- if existing_task.exception() is not None:
140
- logger.info(f"消费者 '{client_name}' 任务异常,重启")
141
- existing_task.cancel()
142
- else:
143
- logger.info(f"消费者 '{client_name}' 已在运行中,无需重复启动")
144
- return
145
- else:
146
- logger.info(f"消费者 '{client_name}' 任务已完成,重新启动")
147
-
148
- if client_name not in cls._clients:
149
- raise ValueError(f"RabbitMQ客户端 '{client_name}' 未初始化")
150
-
151
- client = cls._clients[client_name]
152
- handler = cls._message_handlers.get(client_name)
153
-
154
- if not handler:
155
- logger.warning(f"未找到客户端 '{client_name}' 的处理器")
156
- return
157
-
158
- # 设置消息处理器
159
- await client.set_message_handler(handler)
160
-
161
- # 确保客户端已连接
162
- start_time = asyncio.get_event_loop().time()
163
- while not await client.is_connected and not cls._is_shutdown:
164
- if asyncio.get_event_loop().time() - start_time > cls.CONSUMER_START_TIMEOUT:
165
- raise TimeoutError(f"等待客户端 '{client_name}' 连接超时")
166
-
167
- logger.info(f"等待客户端 '{client_name}' 连接就绪...")
168
- await asyncio.sleep(1)
169
- if cls._is_shutdown:
170
- return
171
-
172
- # 创建停止事件
173
- stop_event = asyncio.Event()
174
- cls._consumer_events[client_name] = stop_event
175
-
176
- # 定义消费任务
177
- async def consume_task():
178
- try:
179
- # 启动消费,带重试机制
180
- max_attempts = 3
181
- attempt = 0
182
- consumer_tag = None
183
-
184
- while attempt < max_attempts and not stop_event.is_set() and not cls._is_shutdown:
185
- try:
186
- # 启动消费前再次校验
187
- if not await client.is_connected:
188
- logger.info(f"消费者 '{client_name}' 连接断开,尝试重连")
189
- await client.connect()
190
-
191
- if not client._queue:
192
- raise Exception("队列未初始化完成")
193
- if not client._message_handler:
194
- raise Exception("消息处理器未设置")
195
-
196
- consumer_tag = await client.start_consuming()
197
- if consumer_tag:
198
- break
199
- except Exception as e:
200
- attempt += 1
201
- logger.warning(
202
- f"启动消费者尝试 {attempt}/{max_attempts} 失败: {str(e)}")
203
- if attempt < max_attempts:
204
- await asyncio.sleep(2)
205
-
206
- if cls._is_shutdown:
207
- return
208
-
209
- if not consumer_tag:
210
- raise Exception(f"经过 {max_attempts} 次尝试仍无法启动消费者")
211
-
212
- # 记录消费者标签
213
- cls._consumer_tags[client_name] = consumer_tag
214
- logger.info(
215
- f"消费者 '{client_name}' 开始消费(单通道),tag: {consumer_tag}"
216
- )
217
-
218
- # 等待停止事件
219
- await stop_event.wait()
220
- logger.info(f"收到停止信号,消费者 '{client_name}' 准备退出")
221
-
222
- except asyncio.CancelledError:
223
- logger.info(f"消费者 '{client_name}' 被取消")
224
- except Exception as e:
225
- logger.error(
226
- f"消费者 '{client_name}' 错误: {str(e)}", exc_info=True)
227
- # 非主动停止时尝试重启
228
- if not stop_event.is_set() and not cls._is_shutdown:
229
- logger.info(f"尝试重启消费者 '{client_name}'")
230
- await asyncio.sleep(cls.RECONNECT_INTERVAL)
231
- asyncio.create_task(cls.start_consumer(client_name))
232
- finally:
233
- # 清理资源
234
- try:
235
- await client.stop_consuming()
236
- except Exception as e:
237
- logger.error(f"停止消费者 '{client_name}' 时出错: {str(e)}")
238
-
239
- # 移除状态记录
240
- if client_name in cls._consumer_tags:
241
- del cls._consumer_tags[client_name]
242
- if client_name in cls._consumer_events:
243
- del cls._consumer_events[client_name]
244
-
245
- logger.info(f"消费者 '{client_name}' 已停止")
246
-
247
- # 创建并跟踪消费任务
248
- task = asyncio.create_task(
249
- consume_task(), name=f"consumer-{client_name}")
250
- cls._consumer_tasks[client_name] = task
251
-
252
- # 添加任务完成回调
253
- def task_done_callback(t: asyncio.Task) -> None:
254
- try:
255
- if t.done():
256
- t.result()
257
- except Exception as e:
258
- logger.error(f"消费者任务 '{client_name}' 异常结束: {str(e)}")
259
- if client_name in cls._message_handlers and not cls._is_shutdown:
260
- asyncio.create_task(cls.start_consumer(client_name))
261
-
262
- task.add_done_callback(task_done_callback)
263
- logger.info(f"消费者任务 '{client_name}' 已创建")
264
-
265
- @classmethod
266
- async def shutdown_consumers(cls, timeout: float = 15.0) -> None:
267
- """关闭所有消费者"""
268
- # 停止所有消费者任务
269
- for client_name, task in cls._consumer_tasks.items():
270
- if not task.done():
271
- # 触发停止事件
272
- if client_name in cls._consumer_events:
273
- cls._consumer_events[client_name].set()
274
- # 取消任务
275
- task.cancel()
276
- try:
277
- await asyncio.wait_for(task, timeout=timeout)
278
- except Exception as e:
279
- logger.error(f"关闭消费者 '{client_name}' 失败: {str(e)}")
280
-
281
- # 清理消费者状态
282
- cls._message_handlers.clear()
283
- cls._consumer_tasks.clear()
284
- cls._consumer_events.clear()
285
- cls._consumer_tags.clear()
@@ -1,117 +0,0 @@
1
- import asyncio
2
- from typing import Optional
3
-
4
- from sycommon.logging.kafka_log import SYLogger
5
- from sycommon.rabbitmq.rabbitmq_client import RabbitMQConnectionPool
6
-
7
- logger = SYLogger
8
-
9
-
10
- class RabbitMQCoreService:
11
- """
12
- RabbitMQ核心服务类 - 负责基础初始化、连接池管理、全局状态控制
13
- """
14
- # 全局共享状态
15
- _config: Optional[dict] = None
16
- _connection_pool: Optional[RabbitMQConnectionPool] = None
17
- _is_shutdown: bool = False
18
- _shutdown_lock = asyncio.Lock()
19
-
20
- # 配置常量
21
- RECONNECT_INTERVAL = 15 # 重连基础间隔(秒)
22
- CONNECTION_POOL_TIMEOUT = 30 # 连接池初始化超时(秒)
23
-
24
- @classmethod
25
- def init_config(cls, config: dict) -> None:
26
- """初始化基础配置(从Nacos加载)"""
27
- from sycommon.synacos.nacos_service import NacosService
28
-
29
- if cls._config:
30
- logger.warning("RabbitMQ配置已初始化,无需重复调用")
31
- return
32
-
33
- # 从Nacos获取MQ配置
34
- cls._config = NacosService(config).share_configs.get(
35
- "mq.yml", {}).get('spring', {}).get('rabbitmq', {})
36
- cls._config["APP_NAME"] = config.get("Name", "")
37
-
38
- # 打印关键配置信息
39
- logger.info(
40
- f"RabbitMQ服务初始化 - 集群节点: {cls._config.get('host')}, "
41
- f"端口: {cls._config.get('port')}, "
42
- f"虚拟主机: {cls._config.get('virtual-host')}, "
43
- f"应用名: {cls._config.get('APP_NAME')}, "
44
- f"心跳: {cls._config.get('heartbeat', 30)}s"
45
- )
46
- cls._is_shutdown = False
47
-
48
- @classmethod
49
- async def init_connection_pool(cls) -> None:
50
- """初始化单通道连接池(带重试机制)"""
51
- if cls._connection_pool or not cls._config or cls._is_shutdown:
52
- return
53
-
54
- try:
55
- # 解析集群节点
56
- hosts_str = cls._config.get('host', "")
57
- hosts_list = [host.strip()
58
- for host in hosts_str.split(',') if host.strip()]
59
- if not hosts_list:
60
- raise ValueError("RabbitMQ集群配置为空,请检查host参数")
61
-
62
- global_prefetch_count = cls._config.get('prefetch_count', 2)
63
-
64
- # 创建单通道连接池
65
- cls._connection_pool = RabbitMQConnectionPool(
66
- hosts=hosts_list,
67
- port=cls._config.get('port', 5672),
68
- username=cls._config.get('username', ""),
69
- password=cls._config.get('password', ""),
70
- virtualhost=cls._config.get('virtual-host', "/"),
71
- app_name=cls._config.get("APP_NAME", ""),
72
- prefetch_count=global_prefetch_count,
73
- heartbeat=cls._config.get('heartbeat', 15),
74
- connection_timeout=cls._config.get('connection_timeout', 15),
75
- reconnect_interval=cls._config.get('reconnect_interval', 5),
76
- )
77
-
78
- # 初始化连接池
79
- await asyncio.wait_for(cls._connection_pool.init_pools(), timeout=cls.CONNECTION_POOL_TIMEOUT)
80
- logger.info("RabbitMQ单通道连接池初始化成功")
81
-
82
- except Exception as e:
83
- logger.error(f"RabbitMQ连接池初始化失败: {str(e)}", exc_info=True)
84
- # 连接池初始化失败时重试(未关闭状态下)
85
- if not cls._is_shutdown:
86
- await asyncio.sleep(cls.RECONNECT_INTERVAL)
87
- asyncio.create_task(cls.init_connection_pool())
88
-
89
- @classmethod
90
- async def wait_for_pool_ready(cls) -> None:
91
- """等待连接池就绪(带超时)"""
92
- if not cls._config:
93
- raise ValueError("RabbitMQ配置尚未初始化,请先调用init_config方法")
94
-
95
- start_time = asyncio.get_event_loop().time()
96
- while not (cls._connection_pool and cls._connection_pool._initialized) and not cls._is_shutdown:
97
- if asyncio.get_event_loop().time() - start_time > cls.CONNECTION_POOL_TIMEOUT:
98
- raise TimeoutError("等待连接池初始化超时")
99
- await asyncio.sleep(1)
100
-
101
- if cls._is_shutdown:
102
- raise RuntimeError("服务关闭中,取消等待连接池")
103
-
104
- @classmethod
105
- async def shutdown_core_resources(cls, timeout: float = 15.0) -> None:
106
- """关闭核心资源(连接池)"""
107
- # 关闭连接池
108
- if cls._connection_pool and cls._connection_pool._initialized:
109
- try:
110
- await cls._connection_pool.close()
111
- logger.info("RabbitMQ单通道连接池已关闭")
112
- except Exception as e:
113
- logger.error(f"关闭连接池失败: {str(e)}")
114
-
115
- # 清理核心状态
116
- cls._config = None
117
- cls._connection_pool = None
@@ -1,238 +0,0 @@
1
- from typing import List, Optional, Union, Dict, Any
2
- import asyncio
3
- import json
4
- import time
5
- from pydantic import BaseModel
6
-
7
- from sycommon.logging.kafka_log import SYLogger
8
- from sycommon.models.mqsend_config import RabbitMQSendConfig
9
- from sycommon.config.Config import Config
10
- from sycommon.models.sso_user import SsoUser
11
- from sycommon.models.mqmsg_model import MQMsgModel
12
- from sycommon.rabbitmq.rabbitmq_client import RabbitMQClient
13
- from sycommon.rabbitmq.rabbitmq_service_client_manager import RabbitMQClientManager
14
-
15
- logger = SYLogger
16
-
17
-
18
- class RabbitMQProducerManager(RabbitMQClientManager):
19
- """
20
- RabbitMQ生产者管理类 - 负责发送器设置、消息发送
21
- """
22
- # 发送器相关状态
23
- _sender_client_names: List[str] = []
24
-
25
- @classmethod
26
- async def setup_senders(cls, senders: List[RabbitMQSendConfig], has_listeners: bool = False, **kwargs) -> None:
27
- """设置消息发送器(适配client_type参数,确保发送器不创建队列)"""
28
- if cls._is_shutdown:
29
- logger.warning("服务已关闭,无法设置发送器")
30
- return
31
-
32
- cls.set_mode_flags(has_listeners=has_listeners, has_senders=True)
33
- logger.info(f"开始设置 {len(senders)} 个消息发送器,纯发送器模式: {not has_listeners}")
34
-
35
- for idx, sender_config in enumerate(senders):
36
- try:
37
- if not sender_config.queue_name:
38
- raise ValueError(f"发送器配置第{idx+1}项缺少queue_name")
39
-
40
- prefetch_count = sender_config.prefetch_count
41
- queue_name = sender_config.queue_name
42
- app_name = cls._config.get(
43
- "APP_NAME", "") if cls._config else ""
44
-
45
- # 处理发送器客户端名称(非队列名)
46
- normalized_name = queue_name
47
- if app_name and normalized_name.endswith(f".{app_name}"):
48
- normalized_name = normalized_name[:-len(f".{app_name}")]
49
- logger.info(f"发送器客户端名称移除app-name后缀: {normalized_name}")
50
-
51
- # 检查是否已初始化
52
- if normalized_name in cls._sender_client_names:
53
- logger.info(f"发送客户端 '{normalized_name}' 已存在,跳过")
54
- continue
55
-
56
- # ===== 处理已有客户端重连 =====
57
- if normalized_name in cls._clients:
58
- client = cls._clients[normalized_name]
59
- if not await client.is_connected:
60
- client.queue_name = normalized_name
61
- client.create_if_not_exists = False
62
- await client.connect()
63
- else:
64
- client = await cls.get_client(
65
- client_name=normalized_name,
66
- client_type="sender",
67
- exchange_type=sender_config.exchange_type,
68
- durable=sender_config.durable,
69
- auto_delete=sender_config.auto_delete,
70
- auto_parse_json=sender_config.auto_parse_json,
71
- queue_name=queue_name,
72
- create_if_not_exists=False,
73
- prefetch_count=prefetch_count,
74
- **kwargs
75
- )
76
-
77
- # 记录客户端
78
- if normalized_name not in cls._clients:
79
- cls._clients[normalized_name] = client
80
- logger.info(f"发送客户端 '{normalized_name}' 已添加")
81
-
82
- if normalized_name not in cls._sender_client_names:
83
- cls._sender_client_names.append(normalized_name)
84
- logger.info(f"发送客户端 '{normalized_name}' 初始化成功(纯发送器模式)")
85
-
86
- except Exception as e:
87
- logger.error(
88
- f"初始化发送客户端第{idx+1}项失败: {str(e)}", exc_info=True)
89
-
90
- logger.info(
91
- f"消息发送器设置完成,共 {len(cls._sender_client_names)} 个发送器,纯发送器模式: {not has_listeners}")
92
-
93
- @classmethod
94
- async def get_sender(cls, queue_name: str) -> Optional[RabbitMQClient]:
95
- """获取发送客户端"""
96
- if cls._is_shutdown:
97
- logger.warning("服务已关闭,无法获取发送器")
98
- return None
99
-
100
- if not queue_name:
101
- logger.warning("发送器名称不能为空")
102
- return None
103
-
104
- # 检查是否在已注册的发送器中
105
- if queue_name in cls._sender_client_names and queue_name in cls._clients:
106
- client = cls._clients[queue_name]
107
- if await client.is_connected:
108
- return client
109
- else:
110
- logger.info(f"发送器 '{queue_name}' 连接已断开,尝试重连")
111
- try:
112
- client.create_if_not_exists = False
113
- await client.connect()
114
- if await client.is_connected:
115
- return client
116
- except Exception as e:
117
- logger.error(f"发送器 '{queue_name}' 重连失败: {str(e)}")
118
- return None
119
-
120
- # 检查是否带有app-name后缀
121
- app_name = cls._config.get("APP_NAME", "") if cls._config else ""
122
- if app_name:
123
- suffixed_name = f"{queue_name}.{app_name}"
124
- if suffixed_name in cls._sender_client_names and suffixed_name in cls._clients:
125
- client = cls._clients[suffixed_name]
126
- if await client.is_connected:
127
- return client
128
- else:
129
- logger.info(f"发送器 '{suffixed_name}' 连接已断开,尝试重连")
130
- try:
131
- client.create_if_not_exists = False
132
- await client.connect()
133
- if await client.is_connected:
134
- return client
135
- except Exception as e:
136
- logger.error(f"发送器 '{suffixed_name}' 重连失败: {str(e)}")
137
-
138
- logger.info(f"未找到可用的发送器 '{queue_name}'")
139
- return None
140
-
141
- @classmethod
142
- async def send_message(
143
- cls,
144
- data: Union[BaseModel, str, Dict[str, Any], None],
145
- queue_name: str, **kwargs
146
- ) -> None:
147
- """发送消息到指定队列"""
148
- if cls._is_shutdown:
149
- raise RuntimeError("RabbitMQService已关闭,无法发送消息")
150
-
151
- # 获取发送客户端
152
- sender = await cls.get_sender(queue_name)
153
- if not sender:
154
- error_msg = f"未找到可用的RabbitMQ发送器 (queue_name: {queue_name})"
155
- logger.error(error_msg)
156
- raise ValueError(error_msg)
157
-
158
- # 确保连接有效
159
- if not await sender.is_connected:
160
- logger.info(f"发送器 '{queue_name}' 连接已关闭,尝试重新连接")
161
- max_retry = 3
162
- retry_count = 0
163
- last_exception = None
164
-
165
- while retry_count < max_retry and not cls._is_shutdown:
166
- try:
167
- sender.create_if_not_exists = False
168
- await sender.connect()
169
- if await sender.is_connected:
170
- logger.info(
171
- f"发送器 '{queue_name}' 第 {retry_count + 1} 次重连成功")
172
- break
173
- except Exception as e:
174
- last_exception = e
175
- retry_count += 1
176
- logger.warning(
177
- f"发送器 '{queue_name}' 第 {retry_count} 次重连失败: {str(e)}")
178
- await asyncio.sleep(cls.RECONNECT_INTERVAL)
179
-
180
- if retry_count >= max_retry and not await sender.is_connected:
181
- error_msg = f"发送器 '{queue_name}' 经过 {max_retry} 次重连仍失败"
182
- logger.error(f"{error_msg}: {str(last_exception)}")
183
- raise Exception(error_msg) from last_exception
184
-
185
- try:
186
- # 处理消息数据
187
- msg_content = ""
188
- if isinstance(data, str):
189
- msg_content = data
190
- elif isinstance(data, BaseModel):
191
- msg_content = data.model_dump_json()
192
- elif isinstance(data, dict):
193
- msg_content = json.dumps(data, ensure_ascii=False)
194
-
195
- # 创建标准消息模型
196
- mq_message = MQMsgModel(
197
- topicCode=queue_name.split('.')[0] if queue_name else "",
198
- msg=msg_content,
199
- correlationDataId=kwargs.get(
200
- 'correlationDataId', logger.get_trace_id()),
201
- groupId=kwargs.get('groupId', ''),
202
- dataKey=kwargs.get('dataKey', ""),
203
- manualFlag=kwargs.get('manualFlag', False),
204
- traceId=logger.get_trace_id()
205
- )
206
-
207
- # 构建消息头
208
- namespaceId = Config().config.get('Nacos', {}).get('namespaceId', '')
209
- tenant_id = "T000002" if namespaceId == "prod" or namespaceId == "wsuat1" else "T000003"
210
- mq_header = {
211
- "context": SsoUser(
212
- tenant_id=tenant_id,
213
- customer_id="SYSTEM",
214
- user_id="SYSTEM",
215
- user_name="SYSTEM",
216
- request_path="/",
217
- req_type="SYSTEM",
218
- trace_id=logger.get_trace_id(),
219
- ).model_dump_json(),
220
- "tenant_id": logger.get_trace_id(),
221
- "createTime": str(int(time.time() * 1000)),
222
- }
223
-
224
- # 发送消息
225
- await sender.publish(
226
- message_body=mq_message.model_dump_json(),
227
- headers=mq_header,
228
- content_type="application/json"
229
- )
230
- logger.info(f"消息发送成功 (队列: {queue_name})")
231
- except Exception as e:
232
- logger.error(f"消息发送失败: {str(e)}", exc_info=True)
233
- raise
234
-
235
- @classmethod
236
- def clear_senders(cls) -> None:
237
- """清理发送器状态"""
238
- cls._sender_client_names.clear()
File without changes
@@ -1,35 +0,0 @@
1
- import sentry_sdk
2
- from datetime import datetime
3
- from sycommon.config.Config import Config
4
- from sycommon.logging.kafka_log import SYLogger
5
- from sentry_sdk.integrations.fastapi import FastApiIntegration
6
- # from sentry_sdk.integrations.logging import LoggingIntegration
7
-
8
-
9
- def sy_sentry_init():
10
- config = Config().config
11
- server_name = config.get('Name', '')
12
- environment = config.get('Nacos', {}).get('namespaceId', '')
13
- sentry_configs = config.get('SentryConfig', [])
14
- target_config = next(
15
- (item for item in sentry_configs if item.get('name') == server_name), None)
16
- if target_config:
17
- target_dsn = target_config.get('dsn')
18
- target_enable = target_config.get('enable')
19
- current_version = datetime.now().strftime("%Y-%m-%d %H:%M:%S-version")
20
- if target_config and target_dsn and target_enable:
21
- try:
22
- sentry_sdk.init(
23
- dsn=target_dsn,
24
- traces_sample_rate=1.0,
25
- server_name=server_name,
26
- environment=environment,
27
- release=current_version,
28
- integrations=[
29
- FastApiIntegration(),
30
- # LoggingIntegration(level=logging.INFO,
31
- # event_level=logging.ERROR)
32
- ],
33
- )
34
- except Exception as e:
35
- SYLogger.error(f"Sentry初始化失败: {str(e)}")