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.
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/PKG-INFO +1 -1
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/pyproject.toml +1 -1
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/rabbitmq/rabbitmq_client.py +84 -77
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/rabbitmq/rabbitmq_service.py +13 -13
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/services.py +4 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/PKG-INFO +1 -1
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/README.md +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/setup.cfg +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/command/cli.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/__init__.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/Config.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/DatabaseConfig.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/EmbeddingConfig.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/LLMConfig.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/MQConfig.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/RerankerConfig.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/__init__.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/database/base_db_service.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/database/database_service.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/health/__init__.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/health/health_check.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/health/metrics.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/health/ping.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/logging/__init__.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/logging/kafka_log.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/logging/logger_wrapper.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/logging/sql_logger.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/__init__.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/context.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/cors.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/docs.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/exception.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/middleware.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/monitor_memory.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/mq.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/timeout.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/traceid.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/__init__.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/base_http.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/log.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/mqlistener_config.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/mqmsg_model.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/mqsend_config.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/sso_user.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/rabbitmq/rabbitmq_pool.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/sse/__init__.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/sse/event.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/sse/sse.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/__init__.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/example.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/example2.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/feign.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/feign_client.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/nacos_service.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/param.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/tools/__init__.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/tools/docs.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/tools/snowflake.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/tools/timing.py +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/SOURCES.txt +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/dependency_links.txt +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/entry_points.txt +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/requires.txt +0 -0
- {sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/top_level.txt +0 -0
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/rabbitmq/rabbitmq_client.py
RENAMED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
328
|
+
if self._tracking_messages:
|
|
328
329
|
logger.warning(
|
|
329
|
-
f"消费停滞,但有 {len(self.
|
|
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(
|
|
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.
|
|
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
|
-
|
|
378
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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=
|
|
489
|
+
timeout=5
|
|
492
490
|
)
|
|
493
491
|
if not confirmed:
|
|
494
492
|
raise Exception("消息未被服务器确认接收")
|
|
495
493
|
|
|
496
494
|
self._update_activity_timestamp()
|
|
497
|
-
logger.
|
|
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"
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
581
|
-
logger.info(
|
|
582
|
-
|
|
583
|
-
while self.
|
|
584
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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} 已达到最大重试次数
|
|
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.
|
|
676
|
-
self.
|
|
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()
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/rabbitmq/rabbitmq_service.py
RENAMED
|
@@ -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.
|
|
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',
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
299
|
+
logger.info(f"发送器队列名称移除app-name后缀: {normalized_name}")
|
|
300
300
|
|
|
301
301
|
# 检查是否已初始化
|
|
302
302
|
if normalized_name in cls._sender_client_names:
|
|
303
|
-
logger.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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 =
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/DatabaseConfig.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/EmbeddingConfig.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/config/RerankerConfig.py
RENAMED
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/database/base_db_service.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/database/database_service.py
RENAMED
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/health/health_check.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/logging/logger_wrapper.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/logging/sql_logger.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/__init__.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/context.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/exception.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/middleware.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/monitor_memory.py
RENAMED
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/timeout.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/traceid.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/mqlistener_config.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/mqmsg_model.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/models/mqsend_config.py
RENAMED
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/rabbitmq/rabbitmq_pool.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/feign_client.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.31 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/nacos_service.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|