sycommon-python-lib 0.1.32__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.32 → sycommon_python_lib-0.1.33}/PKG-INFO +1 -1
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/pyproject.toml +1 -1
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/rabbitmq/rabbitmq_client.py +58 -73
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/rabbitmq/rabbitmq_service.py +1 -1
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/services.py +4 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/PKG-INFO +1 -1
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/README.md +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/setup.cfg +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/command/cli.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/__init__.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/config/Config.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/config/DatabaseConfig.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/config/EmbeddingConfig.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/config/LLMConfig.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/config/MQConfig.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/config/RerankerConfig.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/config/__init__.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/database/base_db_service.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/database/database_service.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/health/__init__.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/health/health_check.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/health/metrics.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/health/ping.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/logging/__init__.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/logging/kafka_log.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/logging/logger_wrapper.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/logging/sql_logger.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/__init__.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/context.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/cors.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/docs.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/exception.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/middleware.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/monitor_memory.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/mq.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/timeout.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/traceid.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/models/__init__.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/models/base_http.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/models/log.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/models/mqlistener_config.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/models/mqmsg_model.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/models/mqsend_config.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/models/sso_user.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/rabbitmq/rabbitmq_pool.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/sse/__init__.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/sse/event.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/sse/sse.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/__init__.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/example.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/example2.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/feign.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/feign_client.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/nacos_service.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/param.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/tools/__init__.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/tools/docs.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/tools/snowflake.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/tools/timing.py +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/SOURCES.txt +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/dependency_links.txt +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/entry_points.txt +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/requires.txt +0 -0
- {sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon_python_lib.egg-info/top_level.txt +0 -0
{sycommon_python_lib-0.1.32 → 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()
|
|
@@ -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
|
-
"""
|
|
187
|
+
"""从连接池获取资源并初始化(交换机、队列)"""
|
|
192
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
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,32 +309,32 @@ class RabbitMQClient:
|
|
|
320
309
|
await self._recreate_channel()
|
|
321
310
|
continue
|
|
322
311
|
|
|
323
|
-
|
|
312
|
+
current_time = asyncio.get_event_loop().time()
|
|
313
|
+
# 清理消息跟踪记录
|
|
324
314
|
if self._tracking_messages:
|
|
325
|
-
#
|
|
326
|
-
|
|
327
|
-
msg_id for msg_id,
|
|
328
|
-
if
|
|
315
|
+
# 1. 清理已确认的消息
|
|
316
|
+
acked_ids = [
|
|
317
|
+
msg_id for msg_id, info in self._tracking_messages.items()
|
|
318
|
+
if info.get('acked', False)
|
|
329
319
|
]
|
|
330
|
-
|
|
331
|
-
for msg_id in acked_message_ids:
|
|
320
|
+
for msg_id in acked_ids:
|
|
332
321
|
del self._tracking_messages[msg_id]
|
|
333
|
-
if
|
|
334
|
-
logger.info(
|
|
335
|
-
f"清理了 {len(acked_message_ids)} 条已确认的消息跟踪记录")
|
|
322
|
+
if acked_ids:
|
|
323
|
+
logger.info(f"清理了 {len(acked_ids)} 条已确认消息记录")
|
|
336
324
|
|
|
337
325
|
# 检查消费停滞
|
|
338
326
|
if self._is_consuming:
|
|
339
|
-
current_time = asyncio.get_event_loop().time()
|
|
340
327
|
if current_time - self._last_message_processed > self.consumption_stall_threshold:
|
|
341
328
|
if self._tracking_messages:
|
|
342
|
-
logger.
|
|
329
|
+
logger.warning(
|
|
343
330
|
f"消费停滞,但有 {len(self._tracking_messages)} 个消息正在处理,暂不重启")
|
|
344
331
|
else:
|
|
345
|
-
#
|
|
332
|
+
# 无有效消息,重启消费
|
|
333
|
+
logger.info("消费停滞且无消息处理,重启消费")
|
|
346
334
|
await self.stop_consuming()
|
|
347
335
|
await asyncio.sleep(1)
|
|
348
336
|
await self.start_consuming()
|
|
337
|
+
|
|
349
338
|
except Exception as e:
|
|
350
339
|
logger.error(f"监控任务出错: {str(e)}")
|
|
351
340
|
await asyncio.sleep(1)
|
|
@@ -356,21 +345,18 @@ class RabbitMQClient:
|
|
|
356
345
|
|
|
357
346
|
async def _recreate_channel(self) -> None:
|
|
358
347
|
try:
|
|
359
|
-
# 无需手动释放,上下文管理器会自动处理
|
|
360
348
|
self.channel = await self._get_channel()
|
|
361
349
|
await self.channel.set_qos(prefetch_count=self.prefetch_count)
|
|
362
350
|
|
|
363
|
-
#
|
|
351
|
+
# 重新获取交换机和队列
|
|
364
352
|
self.exchange = await self.channel.get_exchange(self.exchange_name)
|
|
365
|
-
|
|
366
|
-
# 重新绑定队列
|
|
367
353
|
if self.queue_name:
|
|
368
354
|
self.queue = await self.channel.get_queue(self.queue_name)
|
|
369
355
|
if self.queue and self.exchange:
|
|
370
356
|
await self._bind_queue(self.channel, self.queue, self.exchange)
|
|
371
357
|
|
|
372
358
|
# 重新开始消费
|
|
373
|
-
if self.
|
|
359
|
+
if self.message_handler:
|
|
374
360
|
await self.start_consuming()
|
|
375
361
|
|
|
376
362
|
logger.info("通道已重建并恢复服务")
|
|
@@ -387,10 +373,9 @@ class RabbitMQClient:
|
|
|
387
373
|
async def keepalive():
|
|
388
374
|
while not self._closed and self.is_connected:
|
|
389
375
|
current_time = asyncio.get_event_loop().time()
|
|
390
|
-
|
|
391
|
-
if current_time - self._last_activity_timestamp > self.connection_pool.heartbeat * 1.5:
|
|
376
|
+
if current_time - self._last_activity_timestamp > self.connection_pool.heartbeat * 2:
|
|
392
377
|
logger.info(
|
|
393
|
-
f"连接 {self.connection_pool.heartbeat*
|
|
378
|
+
f"连接 {self.connection_pool.heartbeat*2}s 无活动,执行保活检查")
|
|
394
379
|
try:
|
|
395
380
|
if self.channel.is_closed:
|
|
396
381
|
logger.warning("连接已关闭,触发重连")
|
|
@@ -411,7 +396,7 @@ class RabbitMQClient:
|
|
|
411
396
|
logger.warning(f"保活检查失败: {str(e)},触发重连")
|
|
412
397
|
await self.connect(force_reconnect=True)
|
|
413
398
|
|
|
414
|
-
await asyncio.sleep(self.connection_pool.heartbeat
|
|
399
|
+
await asyncio.sleep(self.connection_pool.heartbeat)
|
|
415
400
|
|
|
416
401
|
self._keepalive_task = asyncio.create_task(keepalive())
|
|
417
402
|
|
|
@@ -437,7 +422,7 @@ class RabbitMQClient:
|
|
|
437
422
|
async def close(self) -> None:
|
|
438
423
|
"""关闭客户端并释放资源"""
|
|
439
424
|
self._closed = True
|
|
440
|
-
self.
|
|
425
|
+
self._set_is_consuming(False)
|
|
441
426
|
|
|
442
427
|
# 取消所有任务
|
|
443
428
|
for task in [self._keepalive_task, self._reconnect_task,
|
|
@@ -495,14 +480,13 @@ class RabbitMQClient:
|
|
|
495
480
|
max_retries = 2
|
|
496
481
|
while retry_count < max_retries:
|
|
497
482
|
try:
|
|
498
|
-
# 从池获取新通道用于发布(避免长时间占用消费通道)
|
|
499
483
|
async with self.connection_pool.channel_pool.acquire() as publish_channel:
|
|
500
484
|
exchange = await publish_channel.get_exchange(self.exchange_name)
|
|
501
485
|
confirmed = await exchange.publish(
|
|
502
486
|
message,
|
|
503
487
|
routing_key=routing_key or self.routing_key or '#',
|
|
504
488
|
mandatory=True,
|
|
505
|
-
timeout=5
|
|
489
|
+
timeout=5
|
|
506
490
|
)
|
|
507
491
|
if not confirmed:
|
|
508
492
|
raise Exception("消息未被服务器确认接收")
|
|
@@ -510,9 +494,11 @@ class RabbitMQClient:
|
|
|
510
494
|
self._update_activity_timestamp()
|
|
511
495
|
logger.info(f"消息已发布到交换机 '{self.exchange_name}'")
|
|
512
496
|
return
|
|
513
|
-
except (ConnectionClosed, ChannelInvalidStateError):
|
|
497
|
+
except (ConnectionClosed, ChannelInvalidStateError, asyncio.TimeoutError):
|
|
498
|
+
# 覆盖更多异常类型
|
|
514
499
|
retry_count += 1
|
|
515
|
-
logger.warning(f"
|
|
500
|
+
logger.warning(f"连接异常,尝试重连后重新发布 (重试次数: {retry_count})")
|
|
501
|
+
# 主动刷新连接状态
|
|
516
502
|
await self.connect(force_reconnect=True)
|
|
517
503
|
except Exception as e:
|
|
518
504
|
retry_count += 1
|
|
@@ -522,7 +508,6 @@ class RabbitMQClient:
|
|
|
522
508
|
|
|
523
509
|
raise Exception(f"消息发布失败,经过{retry_count}次重试仍未成功")
|
|
524
510
|
|
|
525
|
-
# 以下方法(消息消费相关)逻辑与原有保持一致,仅适配连接池
|
|
526
511
|
def set_message_handler(self, handler):
|
|
527
512
|
self.message_handler = handler
|
|
528
513
|
|
|
@@ -531,9 +516,8 @@ class RabbitMQClient:
|
|
|
531
516
|
logger.info("已经在消费中,返回现有consumer_tag")
|
|
532
517
|
if self._consumer_tag:
|
|
533
518
|
return self._consumer_tag
|
|
534
|
-
# 如果_is_consuming为True但无consumer_tag,重置状态并重新启动
|
|
535
519
|
logger.warning("检测到消费状态异常(无consumer_tag),重置状态后重试")
|
|
536
|
-
self.
|
|
520
|
+
self._set_is_consuming(False)
|
|
537
521
|
|
|
538
522
|
if not self.is_connected:
|
|
539
523
|
await self.connect()
|
|
@@ -544,25 +528,21 @@ class RabbitMQClient:
|
|
|
544
528
|
if not self.message_handler:
|
|
545
529
|
raise Exception("未设置消息处理函数")
|
|
546
530
|
|
|
547
|
-
self._is_consuming = True
|
|
548
|
-
logger.info(f"开始消费队列: {self.actual_queue_name}")
|
|
549
|
-
|
|
550
531
|
try:
|
|
551
|
-
# 调用队列的consume方法,确保获取到consumer_tag
|
|
552
532
|
self._consumer_tag = await self.queue.consume(
|
|
553
533
|
self._message_wrapper,
|
|
554
534
|
no_ack=False # 手动确认消息
|
|
555
535
|
)
|
|
556
536
|
|
|
557
|
-
# 确保consumer_tag有效
|
|
558
537
|
if not self._consumer_tag:
|
|
559
538
|
raise Exception("未能获取到有效的consumer_tag")
|
|
560
539
|
|
|
540
|
+
self._set_is_consuming(True)
|
|
561
541
|
logger.info(
|
|
562
542
|
f"消费者已启动,队列: {self.actual_queue_name}, tag: {self._consumer_tag}")
|
|
563
543
|
return self._consumer_tag
|
|
564
544
|
except Exception as e:
|
|
565
|
-
self.
|
|
545
|
+
self._set_is_consuming(False)
|
|
566
546
|
logger.error(f"启动消费失败: {str(e)}", exc_info=True)
|
|
567
547
|
raise
|
|
568
548
|
|
|
@@ -585,22 +565,25 @@ class RabbitMQClient:
|
|
|
585
565
|
if not self._is_consuming:
|
|
586
566
|
return
|
|
587
567
|
|
|
588
|
-
self.
|
|
568
|
+
self._set_is_consuming(False)
|
|
589
569
|
|
|
590
570
|
if self._consumer_tag and self.queue:
|
|
591
571
|
await self._safe_cancel_consumer()
|
|
592
572
|
|
|
593
573
|
# 等待所有正在处理的消息完成
|
|
594
574
|
if self._tracking_messages:
|
|
595
|
-
logger.info(
|
|
596
|
-
|
|
575
|
+
logger.info(f"等待 {len(self._tracking_messages)} 个正在处理的消息完成...")
|
|
576
|
+
wait_start = asyncio.get_event_loop().time()
|
|
597
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
|
|
598
582
|
await asyncio.sleep(1)
|
|
599
583
|
|
|
600
584
|
# 清理状态
|
|
601
585
|
self._consumer_tag = None
|
|
602
586
|
self._tracking_messages.clear()
|
|
603
|
-
|
|
604
587
|
logger.info(f"已停止消费队列: {self.actual_queue_name}")
|
|
605
588
|
|
|
606
589
|
async def _parse_message(self, message: AbstractIncomingMessage) -> Union[Dict[str, Any], str]:
|
|
@@ -620,8 +603,7 @@ class RabbitMQClient:
|
|
|
620
603
|
|
|
621
604
|
async def _message_wrapper(self, message: AbstractIncomingMessage) -> None:
|
|
622
605
|
if not self.message_handler or not self._is_consuming:
|
|
623
|
-
logger.warning("
|
|
624
|
-
# await message.ack()
|
|
606
|
+
logger.warning("未设置消息处理器或已停止消费,拒绝消息,重新放到队列")
|
|
625
607
|
try:
|
|
626
608
|
await message.reject(requeue=True)
|
|
627
609
|
except Exception as e:
|
|
@@ -634,21 +616,23 @@ class RabbitMQClient:
|
|
|
634
616
|
await message.ack()
|
|
635
617
|
return
|
|
636
618
|
|
|
637
|
-
|
|
619
|
+
start_time = asyncio.get_event_loop().time()
|
|
638
620
|
self._tracking_messages[message_id] = {
|
|
639
621
|
'delivery_tag': message.delivery_tag,
|
|
640
622
|
'acked': False,
|
|
641
|
-
'channel_number': self.channel.number if self.channel else None
|
|
623
|
+
'channel_number': self.channel.number if self.channel else None,
|
|
624
|
+
'start_time': start_time
|
|
642
625
|
}
|
|
643
626
|
|
|
644
627
|
try:
|
|
645
628
|
logger.info(f"收到队列 {self.actual_queue_name} 的消息: {message_id}")
|
|
629
|
+
print(f"收到队列 {self.actual_queue_name} 的消息: {message_id}")
|
|
646
630
|
|
|
647
631
|
parsed_data = await self._parse_message(message)
|
|
648
632
|
await self.message_handler(MQMsgModel(** parsed_data), message)
|
|
649
633
|
|
|
650
634
|
await message.ack()
|
|
651
|
-
self._tracking_messages[message_id]['acked'] = True
|
|
635
|
+
self._tracking_messages[message_id]['acked'] = True
|
|
652
636
|
self._update_activity_timestamp()
|
|
653
637
|
self._update_message_processed_timestamp()
|
|
654
638
|
logger.info(f"消息 {message_id} 处理完成并确认")
|
|
@@ -665,9 +649,9 @@ class RabbitMQClient:
|
|
|
665
649
|
|
|
666
650
|
if retry_count >= MAX_RETRY_COUNT:
|
|
667
651
|
logger.error(
|
|
668
|
-
f"消息 {message_id} 已达到最大重试次数
|
|
652
|
+
f"消息 {message_id} 已达到最大重试次数{MAX_RETRY_COUNT},标记为失败")
|
|
669
653
|
await message.ack()
|
|
670
|
-
self._tracking_messages[message_id]['acked'] = True
|
|
654
|
+
self._tracking_messages[message_id]['acked'] = True
|
|
671
655
|
self._update_activity_timestamp()
|
|
672
656
|
return
|
|
673
657
|
|
|
@@ -682,7 +666,7 @@ class RabbitMQClient:
|
|
|
682
666
|
)
|
|
683
667
|
|
|
684
668
|
await message.reject(requeue=False)
|
|
685
|
-
self._tracking_messages[message_id]['acked'] = True
|
|
669
|
+
self._tracking_messages[message_id]['acked'] = True
|
|
686
670
|
|
|
687
671
|
if self.exchange:
|
|
688
672
|
await self.exchange.publish(
|
|
@@ -696,6 +680,7 @@ class RabbitMQClient:
|
|
|
696
680
|
finally:
|
|
697
681
|
if message_id in self._tracking_messages:
|
|
698
682
|
del self._tracking_messages[message_id]
|
|
683
|
+
logger.info(f"已删除消息跟踪信息: {message_id}")
|
|
699
684
|
|
|
700
685
|
async def __aenter__(self):
|
|
701
686
|
await self.connect()
|
|
@@ -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.32 → sycommon_python_lib-0.1.33}/src/sycommon/config/DatabaseConfig.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.32 → 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.32 → sycommon_python_lib-0.1.33}/src/sycommon/config/RerankerConfig.py
RENAMED
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/database/base_db_service.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/database/database_service.py
RENAMED
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.32 → 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.32 → sycommon_python_lib-0.1.33}/src/sycommon/logging/logger_wrapper.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/logging/sql_logger.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/__init__.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.32 → 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.32 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/exception.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/middleware.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/monitor_memory.py
RENAMED
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/middleware/timeout.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.32 → 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.32 → sycommon_python_lib-0.1.33}/src/sycommon/models/mqlistener_config.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/models/mqmsg_model.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.32 → sycommon_python_lib-0.1.33}/src/sycommon/models/mqsend_config.py
RENAMED
|
File without changes
|
|
File without changes
|
{sycommon_python_lib-0.1.32 → 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.32 → sycommon_python_lib-0.1.33}/src/sycommon/synacos/feign_client.py
RENAMED
|
File without changes
|
{sycommon_python_lib-0.1.32 → 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
|