sycommon-python-lib 0.1.56b5__tar.gz → 0.1.56b6__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.
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/PKG-INFO +1 -1
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/pyproject.toml +1 -1
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/rabbitmq/rabbitmq_client.py +64 -14
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/rabbitmq/rabbitmq_pool.py +59 -9
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/rabbitmq/rabbitmq_service.py +52 -41
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon_python_lib.egg-info/PKG-INFO +1 -1
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/README.md +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/setup.cfg +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/command/cli.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/__init__.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/config/Config.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/config/DatabaseConfig.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/config/EmbeddingConfig.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/config/LLMConfig.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/config/MQConfig.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/config/RerankerConfig.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/config/__init__.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/database/async_base_db_service.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/database/async_database_service.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/database/base_db_service.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/database/database_service.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/health/__init__.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/health/health_check.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/health/metrics.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/health/ping.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/llm/__init__.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/llm/embedding.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/llm/get_llm.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/llm/llm_logger.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/llm/llm_tokens.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/logging/__init__.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/logging/async_sql_logger.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/logging/kafka_log.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/logging/logger_levels.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/logging/logger_wrapper.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/logging/sql_logger.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/__init__.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/context.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/cors.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/docs.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/exception.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/middleware.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/monitor_memory.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/mq.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/timeout.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/traceid.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/models/__init__.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/models/base_http.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/models/log.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/models/mqlistener_config.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/models/mqmsg_model.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/models/mqsend_config.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/models/sso_user.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/notice/__init__.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/notice/uvicorn_monitor.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/services.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/sse/__init__.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/sse/event.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/sse/sse.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/synacos/__init__.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/synacos/example.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/synacos/example2.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/synacos/feign.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/synacos/feign_client.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/synacos/nacos_service.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/synacos/param.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/tools/__init__.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/tools/docs.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/tools/merge_headers.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/tools/snowflake.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/tools/timing.py +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon_python_lib.egg-info/SOURCES.txt +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon_python_lib.egg-info/dependency_links.txt +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon_python_lib.egg-info/entry_points.txt +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon_python_lib.egg-info/requires.txt +0 -0
- {sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon_python_lib.egg-info/top_level.txt +0 -0
|
@@ -245,7 +245,7 @@ class RabbitMQClient:
|
|
|
245
245
|
logger.info("消息处理器设置成功")
|
|
246
246
|
|
|
247
247
|
async def start_consuming(self) -> Optional[ConsumerTag]:
|
|
248
|
-
"""
|
|
248
|
+
"""启动消息消费(支持自动重连 + Header 重试计数限制)"""
|
|
249
249
|
if self._closed:
|
|
250
250
|
raise RuntimeError("客户端已关闭,无法启动消费")
|
|
251
251
|
|
|
@@ -258,10 +258,11 @@ class RabbitMQClient:
|
|
|
258
258
|
if not self._queue:
|
|
259
259
|
raise RuntimeError("未配置队列名或队列未创建,无法启动消费")
|
|
260
260
|
|
|
261
|
-
# 2.
|
|
261
|
+
# 2. 定义消费回调
|
|
262
262
|
async def consume_callback(message: AbstractIncomingMessage):
|
|
263
263
|
try:
|
|
264
264
|
# 解析消息体
|
|
265
|
+
msg_obj: MQMsgModel
|
|
265
266
|
if self.auto_parse_json:
|
|
266
267
|
try:
|
|
267
268
|
body_dict = json.loads(
|
|
@@ -270,19 +271,26 @@ class RabbitMQClient:
|
|
|
270
271
|
except json.JSONDecodeError as e:
|
|
271
272
|
logger.error(
|
|
272
273
|
f"JSON消息解析失败: {str(e)},消息体: {message.body[:100]}...")
|
|
273
|
-
|
|
274
|
+
# 解析失败通常无法重试,直接丢弃
|
|
275
|
+
await message.nack(requeue=False)
|
|
274
276
|
return
|
|
275
277
|
else:
|
|
276
278
|
msg_obj = MQMsgModel(
|
|
277
279
|
body=message.body.decode("utf-8"),
|
|
278
280
|
routing_key=message.routing_key,
|
|
279
281
|
delivery_tag=message.delivery_tag,
|
|
282
|
+
traceId=message.headers.get("trace-id", None),
|
|
283
|
+
headers=message.headers
|
|
280
284
|
)
|
|
281
285
|
|
|
286
|
+
# 统一追踪ID
|
|
287
|
+
SYLogger.set_trace_id(
|
|
288
|
+
message.headers.get("trace-id", None))
|
|
289
|
+
|
|
282
290
|
# 调用消息处理器
|
|
283
291
|
await self._message_handler(msg_obj, message)
|
|
284
292
|
|
|
285
|
-
#
|
|
293
|
+
# 处理成功,手动ACK
|
|
286
294
|
await message.ack()
|
|
287
295
|
logger.debug(
|
|
288
296
|
f"消息处理成功,delivery_tag: {message.delivery_tag}")
|
|
@@ -292,19 +300,61 @@ class RabbitMQClient:
|
|
|
292
300
|
f"消息处理失败,delivery_tag: {message.delivery_tag}",
|
|
293
301
|
exc_info=True
|
|
294
302
|
)
|
|
295
|
-
|
|
296
|
-
|
|
303
|
+
|
|
304
|
+
# 1. 获取当前重试次数,默认为 0
|
|
305
|
+
current_retry_count = 0
|
|
306
|
+
if message.headers:
|
|
307
|
+
current_retry_count = int(
|
|
308
|
+
message.headers.get("x-retry-count", 0))
|
|
309
|
+
|
|
310
|
+
# 2. 检查是否超过最大重试次数 (3次)
|
|
311
|
+
MAX_RETRY = 3
|
|
312
|
+
if current_retry_count >= MAX_RETRY:
|
|
297
313
|
logger.warning(
|
|
298
|
-
f"
|
|
314
|
+
f"消息重试次数已达上限({MAX_RETRY}),丢弃消息。"
|
|
315
|
+
f"delivery_tag: {message.delivery_tag}, routing_key: {message.routing_key}"
|
|
316
|
+
)
|
|
317
|
+
# 丢弃消息(不重新入队)
|
|
299
318
|
await message.reject(requeue=False)
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
319
|
+
return
|
|
320
|
+
|
|
321
|
+
# 3. 次数未满,准备重入队
|
|
322
|
+
# 注意:AbstractIncomingMessage.headers 是只读的 (frozendict),
|
|
323
|
+
# 不能直接 message.headers["x-retry-count"] = ...
|
|
324
|
+
# 必须重新构造 headers 字典。
|
|
325
|
+
new_headers = dict(
|
|
326
|
+
message.headers) if message.headers else {}
|
|
327
|
+
new_headers["x-retry-count"] = current_retry_count + 1
|
|
328
|
+
|
|
329
|
+
logger.warning(
|
|
330
|
+
f"消息处理失败,准备第 {current_retry_count + 1} 次重入队。"
|
|
331
|
+
f"delivery_tag: {message.delivery_tag}"
|
|
332
|
+
)
|
|
303
333
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
334
|
+
try:
|
|
335
|
+
new_msg = Message(
|
|
336
|
+
body=message.body,
|
|
337
|
+
headers=new_headers,
|
|
338
|
+
content_type=message.content_type,
|
|
339
|
+
delivery_mode=message.delivery_mode
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
# 发布到原 Exchange 和 RoutingKey
|
|
343
|
+
# 注意:这里可能会抛出异常,如果抛异常,消息可能会丢失(因为已经 Nack 掉了)
|
|
344
|
+
await self._exchange.publish(
|
|
345
|
+
new_msg,
|
|
346
|
+
routing_key=message.routing_key
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
# 发布成功后,Ack 掉旧消息
|
|
350
|
+
await message.ack()
|
|
351
|
+
logger.info(
|
|
352
|
+
f"消息已重新发布 (重试次数: {new_headers['x-retry-count']})")
|
|
353
|
+
|
|
354
|
+
except Exception as publish_err:
|
|
355
|
+
logger.error(f"重新发布消息失败(消息丢失): {publish_err}")
|
|
356
|
+
# 重新发布失败,只能丢弃或者 Nack(False)
|
|
357
|
+
await message.reject(requeue=False)
|
|
308
358
|
|
|
309
359
|
# 3. 启动消费(单通道消费,避免阻塞发布需确保业务回调非阻塞)
|
|
310
360
|
self._consumer_tag = await self._queue.consume(consume_callback)
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/rabbitmq/rabbitmq_pool.py
RENAMED
|
@@ -118,23 +118,73 @@ class RabbitMQConnectionPool:
|
|
|
118
118
|
raise
|
|
119
119
|
|
|
120
120
|
async def _ensure_main_channel(self) -> RobustChannel:
|
|
121
|
-
"""确保主通道有效 (原子操作)"""
|
|
121
|
+
"""确保主通道有效 (原子操作 + 自动轮询重试 + 失败清理)"""
|
|
122
122
|
async with self._lock:
|
|
123
123
|
if self._is_shutdown:
|
|
124
124
|
raise RuntimeError("客户端已关闭")
|
|
125
125
|
|
|
126
|
-
#
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
126
|
+
# 如果连接对象不存在或已关闭,进入重连流程
|
|
127
|
+
if self._connection is None or self._connection.is_closed:
|
|
128
|
+
retry_hosts = self.hosts.copy() # 复制一份列表用于重试
|
|
129
|
+
last_error = None
|
|
130
|
+
temp_conn = None # 临时变量,用于引用本次尝试创建的连接
|
|
131
|
+
|
|
132
|
+
# 轮询尝试列表中的每一个 Host
|
|
133
|
+
while retry_hosts:
|
|
134
|
+
host = random.choice(retry_hosts)
|
|
135
|
+
retry_hosts.remove(host) # 从待尝试列表中移除
|
|
136
|
+
|
|
137
|
+
logger.info(f"⚠️ [RECONNECT] 尝试连接节点: {host}")
|
|
138
|
+
self._current_host = host
|
|
139
|
+
temp_conn = None # 重置临时引用
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
conn_url = (
|
|
143
|
+
f"amqp://{self.username}:{self.password}@{host}:{self.port}/"
|
|
144
|
+
f"{self.virtualhost}?name={self.app_name}&heartbeat={self.heartbeat}"
|
|
145
|
+
f"&reconnect_interval={self.reconnect_interval}&fail_fast=1"
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# 尝试连接
|
|
149
|
+
temp_conn = await connect_robust(conn_url, timeout=self.connection_timeout)
|
|
150
|
+
|
|
151
|
+
# --- 关键点:连接成功 ---
|
|
152
|
+
self._connection = temp_conn
|
|
153
|
+
temp_conn = None # 清空临时引用,因为所有权已经移交给 self._connection
|
|
154
|
+
|
|
155
|
+
logger.info(f"🔗 [RECONNECT_OK] 成功连接到节点: {host}")
|
|
156
|
+
last_error = None
|
|
157
|
+
break # 成功,跳出循环
|
|
158
|
+
|
|
159
|
+
except Exception as e:
|
|
160
|
+
logger.warning(
|
|
161
|
+
f"❌ [RECONNECT_FAIL] 节点 {host} 不可用: {str(e)}")
|
|
162
|
+
|
|
163
|
+
# 【核心修复】清理失败的连接对象
|
|
164
|
+
if temp_conn is not None:
|
|
165
|
+
try:
|
|
166
|
+
logger.debug(
|
|
167
|
+
f"🧹 [CLEANUP] 正在关闭失败的连接对象: {id(temp_conn)}")
|
|
168
|
+
# 即使连接对象处于异常状态,close() 通常也是安全的
|
|
169
|
+
await temp_conn.close()
|
|
170
|
+
logger.debug(f"✅ [CLEANUP] 失败连接已关闭")
|
|
171
|
+
except Exception as close_err:
|
|
172
|
+
logger.warning(
|
|
173
|
+
f"⚠️ [CLEANUP_ERR] 关闭失败连接时出错: {str(close_err)}")
|
|
174
|
+
|
|
175
|
+
last_error = e
|
|
176
|
+
asyncio.sleep(self.reconnect_interval)
|
|
177
|
+
continue # 继续试下一个
|
|
178
|
+
|
|
179
|
+
# 如果所有节点都试完了还是失败
|
|
180
|
+
if last_error:
|
|
181
|
+
logger.error("💥 [RECONNECT_FATAL] 所有 RabbitMQ 节点均不可用")
|
|
182
|
+
raise ConnectionError("所有 RabbitMQ 节点连接失败") from last_error
|
|
133
183
|
|
|
134
184
|
# 2. 确保主通道存在
|
|
135
185
|
if self._channel is None or self._channel.is_closed:
|
|
136
186
|
logger.info("⚠️ [RECOVER_CHANNEL] 检测到主通道不存在或已关闭,开始恢复...")
|
|
137
|
-
self._channel = await self._create_channel_impl(
|
|
187
|
+
self._channel = await self._create_channel_impl(self._connection)
|
|
138
188
|
|
|
139
189
|
return self._channel
|
|
140
190
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import json
|
|
3
|
+
import time
|
|
3
4
|
from typing import (
|
|
4
5
|
Callable, Coroutine, Dict, List, Optional, Type, Union, Any
|
|
5
6
|
)
|
|
6
7
|
from pydantic import BaseModel
|
|
7
8
|
from aio_pika.abc import AbstractIncomingMessage, ConsumerTag
|
|
8
9
|
|
|
10
|
+
from sycommon.config.Config import Config
|
|
9
11
|
from sycommon.models.mqmsg_model import MQMsgModel
|
|
10
12
|
from sycommon.models.mqlistener_config import RabbitMQListenerConfig
|
|
11
13
|
from sycommon.models.mqsend_config import RabbitMQSendConfig
|
|
@@ -238,14 +240,16 @@ class RabbitMQService:
|
|
|
238
240
|
|
|
239
241
|
app_name = kwargs.get('app_name', cls._config.get(
|
|
240
242
|
"APP_NAME", "")) if cls._config else ""
|
|
241
|
-
|
|
243
|
+
# 纯发送器场景(没有监听器),强制不创建队列
|
|
244
|
+
is_sender_only = not cls._has_listeners and cls._has_senders
|
|
242
245
|
|
|
243
|
-
#
|
|
244
|
-
create_if_not_exists =
|
|
246
|
+
# 发送器场景下强制禁用队列创建
|
|
247
|
+
create_if_not_exists = False if is_sender_only else (
|
|
248
|
+
cls._has_listeners)
|
|
245
249
|
|
|
246
|
-
# 为监听器队列名称拼接应用名
|
|
247
250
|
processed_queue_name = queue_name
|
|
248
|
-
|
|
251
|
+
# 只有非纯发送器场景才处理队列名称拼接
|
|
252
|
+
if not is_sender_only and create_if_not_exists and processed_queue_name and app_name:
|
|
249
253
|
if not processed_queue_name.endswith(f".{app_name}"):
|
|
250
254
|
processed_queue_name = f"{processed_queue_name}.{app_name}"
|
|
251
255
|
logger.info(f"监听器队列名称自动拼接app-name: {processed_queue_name}")
|
|
@@ -253,8 +257,9 @@ class RabbitMQService:
|
|
|
253
257
|
logger.info(f"监听器队列已包含app-name: {processed_queue_name}")
|
|
254
258
|
|
|
255
259
|
logger.info(
|
|
256
|
-
f"创建客户端 - 队列: {processed_queue_name
|
|
257
|
-
f"
|
|
260
|
+
f"创建客户端 - 队列: {processed_queue_name if not is_sender_only else 'N/A'}, "
|
|
261
|
+
f"纯发送器模式: {is_sender_only}, "
|
|
262
|
+
f"允许创建队列: {create_if_not_exists}"
|
|
258
263
|
)
|
|
259
264
|
|
|
260
265
|
# 创建客户端实例(适配精简版RabbitMQClient参数)
|
|
@@ -263,9 +268,12 @@ class RabbitMQService:
|
|
|
263
268
|
exchange_name=cls._config.get(
|
|
264
269
|
'exchange_name', "system.topic.exchange"),
|
|
265
270
|
exchange_type=kwargs.get('exchange_type', "topic"),
|
|
266
|
-
|
|
271
|
+
# 纯发送器场景下队列名称设为None,避免队列相关操作
|
|
272
|
+
queue_name=None if is_sender_only else processed_queue_name,
|
|
267
273
|
routing_key=kwargs.get(
|
|
268
|
-
'routing_key',
|
|
274
|
+
'routing_key',
|
|
275
|
+
f"{queue_name.split('.')[0]}.#" if queue_name and not is_sender_only else "#"
|
|
276
|
+
),
|
|
269
277
|
durable=kwargs.get('durable', True),
|
|
270
278
|
auto_delete=kwargs.get('auto_delete', False),
|
|
271
279
|
auto_parse_json=kwargs.get('auto_parse_json', True),
|
|
@@ -308,33 +316,32 @@ class RabbitMQService:
|
|
|
308
316
|
# 如果客户端已存在且连接有效,直接返回
|
|
309
317
|
if client_name in cls._clients:
|
|
310
318
|
client = cls._clients[client_name]
|
|
311
|
-
|
|
312
|
-
not kwargs.get('create_if_not_exists', True))
|
|
319
|
+
is_sender_only = not cls._has_listeners and cls._has_senders
|
|
313
320
|
|
|
314
321
|
if await client.is_connected:
|
|
315
|
-
#
|
|
316
|
-
if not
|
|
322
|
+
# 只有非纯发送器场景才检查队列初始化状态
|
|
323
|
+
if not is_sender_only and not client._queue and cls._has_listeners:
|
|
317
324
|
logger.info(f"客户端 '{client_name}' 队列未初始化,重新连接")
|
|
318
325
|
client.create_if_not_exists = True
|
|
319
326
|
await client.connect()
|
|
320
327
|
return client
|
|
321
328
|
else:
|
|
322
329
|
logger.info(f"客户端 '{client_name}' 连接已断开,重新连接")
|
|
323
|
-
if not
|
|
324
|
-
client.create_if_not_exists =
|
|
330
|
+
if not is_sender_only:
|
|
331
|
+
client.create_if_not_exists = cls._has_listeners
|
|
325
332
|
await client.connect()
|
|
326
333
|
return client
|
|
327
334
|
|
|
328
335
|
# 创建新客户端
|
|
329
336
|
initial_queue_name = kwargs.pop('queue_name', '')
|
|
330
|
-
|
|
331
|
-
not kwargs.get('create_if_not_exists', True))
|
|
337
|
+
is_sender_only = not cls._has_listeners and cls._has_senders
|
|
332
338
|
|
|
333
|
-
# 发送器特殊处理
|
|
334
|
-
if
|
|
339
|
+
# 发送器特殊处理 - 纯发送器场景强制不创建队列
|
|
340
|
+
if is_sender_only:
|
|
335
341
|
kwargs['create_if_not_exists'] = False
|
|
342
|
+
# 纯发送器场景下不传递队列名称,避免队列创建
|
|
336
343
|
client = await cls._create_client(
|
|
337
|
-
|
|
344
|
+
"", # 空队列名
|
|
338
345
|
app_name=cls._config.get("APP_NAME", ""),
|
|
339
346
|
**kwargs
|
|
340
347
|
)
|
|
@@ -351,8 +358,8 @@ class RabbitMQService:
|
|
|
351
358
|
**kwargs
|
|
352
359
|
)
|
|
353
360
|
|
|
354
|
-
#
|
|
355
|
-
if not client._queue:
|
|
361
|
+
# 只有非纯发送器场景才验证队列创建
|
|
362
|
+
if not is_sender_only and not client._queue:
|
|
356
363
|
logger.error(f"队列 '{initial_queue_name}' 创建失败,尝试重新创建")
|
|
357
364
|
client.create_if_not_exists = True
|
|
358
365
|
await client.connect()
|
|
@@ -371,7 +378,7 @@ class RabbitMQService:
|
|
|
371
378
|
|
|
372
379
|
cls._has_senders = True
|
|
373
380
|
cls._has_listeners = has_listeners
|
|
374
|
-
logger.info(f"开始设置 {len(senders)}
|
|
381
|
+
logger.info(f"开始设置 {len(senders)} 个消息发送器,纯发送器模式: {not has_listeners}")
|
|
375
382
|
|
|
376
383
|
for idx, sender_config in enumerate(senders):
|
|
377
384
|
try:
|
|
@@ -394,10 +401,12 @@ class RabbitMQService:
|
|
|
394
401
|
logger.info(f"发送客户端 '{normalized_name}' 已存在,跳过")
|
|
395
402
|
continue
|
|
396
403
|
|
|
397
|
-
# 获取或创建客户端
|
|
404
|
+
# 获取或创建客户端 - 强制禁用队列创建
|
|
398
405
|
if normalized_name in cls._clients:
|
|
399
406
|
client = cls._clients[normalized_name]
|
|
400
407
|
if not await client.is_connected:
|
|
408
|
+
# 纯发送器场景下连接时也不创建队列
|
|
409
|
+
client.create_if_not_exists = False
|
|
401
410
|
await client.connect()
|
|
402
411
|
else:
|
|
403
412
|
client = await cls.get_client(
|
|
@@ -407,7 +416,7 @@ class RabbitMQService:
|
|
|
407
416
|
auto_delete=sender_config.auto_delete,
|
|
408
417
|
auto_parse_json=sender_config.auto_parse_json,
|
|
409
418
|
queue_name=queue_name,
|
|
410
|
-
create_if_not_exists=False,
|
|
419
|
+
create_if_not_exists=False, # 强制不创建队列
|
|
411
420
|
prefetch_count=prefetch_count,
|
|
412
421
|
**kwargs
|
|
413
422
|
)
|
|
@@ -419,13 +428,14 @@ class RabbitMQService:
|
|
|
419
428
|
|
|
420
429
|
if normalized_name not in cls._sender_client_names:
|
|
421
430
|
cls._sender_client_names.append(normalized_name)
|
|
422
|
-
logger.info(f"发送客户端 '{normalized_name}'
|
|
431
|
+
logger.info(f"发送客户端 '{normalized_name}' 初始化成功(纯发送器模式)")
|
|
423
432
|
|
|
424
433
|
except Exception as e:
|
|
425
434
|
logger.error(
|
|
426
435
|
f"初始化发送客户端第{idx+1}项失败: {str(e)}", exc_info=True)
|
|
427
436
|
|
|
428
|
-
logger.info(
|
|
437
|
+
logger.info(
|
|
438
|
+
f"消息发送器设置完成,共 {len(cls._sender_client_names)} 个发送器,纯发送器模式: {not has_listeners}")
|
|
429
439
|
|
|
430
440
|
@classmethod
|
|
431
441
|
async def setup_listeners(cls, listeners: List[RabbitMQListenerConfig], has_senders: bool = False, **kwargs) -> None:
|
|
@@ -559,8 +569,8 @@ class RabbitMQService:
|
|
|
559
569
|
handler = cls._message_handlers.get(client_name)
|
|
560
570
|
|
|
561
571
|
if not handler:
|
|
562
|
-
logger.warning(f"未找到客户端 '{client_name}'
|
|
563
|
-
|
|
572
|
+
logger.warning(f"未找到客户端 '{client_name}' 的处理器")
|
|
573
|
+
return
|
|
564
574
|
|
|
565
575
|
# 设置消息处理器
|
|
566
576
|
await client.set_message_handler(handler)
|
|
@@ -671,15 +681,6 @@ class RabbitMQService:
|
|
|
671
681
|
task.add_done_callback(task_done_callback)
|
|
672
682
|
logger.info(f"消费者任务 '{client_name}' 已创建")
|
|
673
683
|
|
|
674
|
-
@classmethod
|
|
675
|
-
async def default_message_handler(cls, parsed_data: MQMsgModel, original_message: AbstractIncomingMessage) -> None:
|
|
676
|
-
"""默认消息处理器"""
|
|
677
|
-
logger.info(f"\n===== 收到消息 [{original_message.routing_key}] =====")
|
|
678
|
-
logger.info(f"关联ID: {parsed_data.correlationDataId}")
|
|
679
|
-
logger.info(f"主题代码: {parsed_data.topicCode}")
|
|
680
|
-
logger.info(f"消息内容: {parsed_data.msg}")
|
|
681
|
-
logger.info("===================\n")
|
|
682
|
-
|
|
683
684
|
@classmethod
|
|
684
685
|
async def get_sender(cls, queue_name: str) -> Optional[RabbitMQClient]:
|
|
685
686
|
"""获取发送客户端(适配单通道池)"""
|
|
@@ -699,6 +700,8 @@ class RabbitMQService:
|
|
|
699
700
|
else:
|
|
700
701
|
logger.info(f"发送器 '{queue_name}' 连接已断开,尝试重连")
|
|
701
702
|
try:
|
|
703
|
+
# 重连时也强制不创建队列
|
|
704
|
+
client.create_if_not_exists = False
|
|
702
705
|
await client.connect()
|
|
703
706
|
if await client.is_connected:
|
|
704
707
|
return client
|
|
@@ -717,6 +720,8 @@ class RabbitMQService:
|
|
|
717
720
|
else:
|
|
718
721
|
logger.info(f"发送器 '{suffixed_name}' 连接已断开,尝试重连")
|
|
719
722
|
try:
|
|
723
|
+
# 重连时也强制不创建队列
|
|
724
|
+
client.create_if_not_exists = False
|
|
720
725
|
await client.connect()
|
|
721
726
|
if await client.is_connected:
|
|
722
727
|
return client
|
|
@@ -752,6 +757,8 @@ class RabbitMQService:
|
|
|
752
757
|
|
|
753
758
|
while retry_count < max_retry and not cls._is_shutdown:
|
|
754
759
|
try:
|
|
760
|
+
# 重连时强制不创建队列
|
|
761
|
+
sender.create_if_not_exists = False
|
|
755
762
|
await sender.connect()
|
|
756
763
|
if await sender.is_connected:
|
|
757
764
|
logger.info(
|
|
@@ -792,16 +799,20 @@ class RabbitMQService:
|
|
|
792
799
|
)
|
|
793
800
|
|
|
794
801
|
# 构建消息头
|
|
802
|
+
namespaceId = Config().config.get('Nacos', {}).get('namespaceId', '未知环境')
|
|
803
|
+
tenant_id = "T000002" if namespaceId == "prod" or namespaceId == "wsuat1" else "T000003"
|
|
795
804
|
mq_header = {
|
|
796
805
|
"context": SsoUser(
|
|
797
|
-
tenant_id=
|
|
806
|
+
tenant_id=tenant_id,
|
|
798
807
|
customer_id="SYSTEM",
|
|
799
808
|
user_id="SYSTEM",
|
|
800
809
|
user_name="SYSTEM",
|
|
801
|
-
request_path="",
|
|
810
|
+
request_path="/",
|
|
802
811
|
req_type="SYSTEM",
|
|
803
812
|
trace_id=logger.get_trace_id(),
|
|
804
|
-
).model_dump_json()
|
|
813
|
+
).model_dump_json(),
|
|
814
|
+
"tenant_id": logger.get_trace_id(),
|
|
815
|
+
"createTime": str(int(time.time() * 1000)),
|
|
805
816
|
}
|
|
806
817
|
|
|
807
818
|
# 发送消息(单通道场景下依赖原生异步确认)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/config/DatabaseConfig.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/config/EmbeddingConfig.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/config/LLMConfig.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/config/MQConfig.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/config/RerankerConfig.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/config/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/health/__init__.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/health/health_check.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/health/metrics.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/llm/llm_logger.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/llm/llm_tokens.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/logging/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/logging/kafka_log.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/logging/logger_levels.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/logging/logger_wrapper.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/logging/sql_logger.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/__init__.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/context.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/cors.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/docs.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/exception.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/middleware.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/timeout.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/middleware/traceid.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/models/__init__.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/models/base_http.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/models/mqmsg_model.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/models/mqsend_config.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/models/sso_user.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/notice/__init__.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/notice/uvicorn_monitor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/synacos/__init__.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/synacos/example.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/synacos/example2.py
RENAMED
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/synacos/feign_client.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/synacos/nacos_service.py
RENAMED
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/tools/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/tools/merge_headers.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.56b5 → sycommon_python_lib-0.1.56b6}/src/sycommon/tools/snowflake.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|