sycommon-python-lib 0.1.32__py3-none-any.whl → 0.1.46__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sycommon/middleware/traceid.py +1 -1
- sycommon/rabbitmq/rabbitmq_client.py +392 -625
- sycommon/rabbitmq/rabbitmq_pool.py +548 -66
- sycommon/rabbitmq/rabbitmq_service.py +369 -165
- sycommon/services.py +59 -22
- sycommon/synacos/feign.py +57 -15
- sycommon/synacos/nacos_service.py +74 -53
- {sycommon_python_lib-0.1.32.dist-info → sycommon_python_lib-0.1.46.dist-info}/METADATA +7 -7
- {sycommon_python_lib-0.1.32.dist-info → sycommon_python_lib-0.1.46.dist-info}/RECORD +12 -12
- {sycommon_python_lib-0.1.32.dist-info → sycommon_python_lib-0.1.46.dist-info}/WHEEL +0 -0
- {sycommon_python_lib-0.1.32.dist-info → sycommon_python_lib-0.1.46.dist-info}/entry_points.txt +0 -0
- {sycommon_python_lib-0.1.32.dist-info → sycommon_python_lib-0.1.46.dist-info}/top_level.txt +0 -0
sycommon/services.py
CHANGED
|
@@ -22,6 +22,7 @@ class Services(metaclass=SingletonMeta):
|
|
|
22
22
|
_instance: Optional['Services'] = None
|
|
23
23
|
_app: Optional[FastAPI] = None
|
|
24
24
|
_user_lifespan: Optional[Callable] = None
|
|
25
|
+
_shutdown_lock: asyncio.Lock = asyncio.Lock()
|
|
25
26
|
|
|
26
27
|
def __init__(self, config: dict, app: FastAPI):
|
|
27
28
|
if not Services._config:
|
|
@@ -66,8 +67,13 @@ class Services(metaclass=SingletonMeta):
|
|
|
66
67
|
if not cls._config:
|
|
67
68
|
config = yaml.safe_load(open('app.yaml', 'r', encoding='utf-8'))
|
|
68
69
|
cls._config = config
|
|
69
|
-
|
|
70
|
-
app.
|
|
70
|
+
# 使用config
|
|
71
|
+
app.state.config = {
|
|
72
|
+
"host": cls._config.get('Host', '0.0.0.0'),
|
|
73
|
+
"port": cls._config.get('Port', 8080),
|
|
74
|
+
"workers": cls._config.get('Workers', 1),
|
|
75
|
+
"h11_max_incomplete_event_size": cls._config.get('H11MaxIncompleteEventSize', 1024 * 1024 * 1024)
|
|
76
|
+
}
|
|
71
77
|
|
|
72
78
|
# 立即配置非异步服务(在应用启动前)
|
|
73
79
|
if middleware:
|
|
@@ -139,10 +145,18 @@ class Services(metaclass=SingletonMeta):
|
|
|
139
145
|
has_listeners: bool = False,
|
|
140
146
|
has_senders: bool = False,
|
|
141
147
|
):
|
|
142
|
-
"""异步设置MQ
|
|
148
|
+
"""异步设置MQ相关服务(适配新的RabbitMQService)"""
|
|
143
149
|
# 初始化RabbitMQ服务,传递状态
|
|
144
150
|
RabbitMQService.init(self._config, has_listeners, has_senders)
|
|
145
151
|
|
|
152
|
+
# 等待RabbitMQ连接池初始化完成(最多等待30秒)
|
|
153
|
+
start_time = asyncio.get_event_loop().time()
|
|
154
|
+
while not RabbitMQService._connection_pool and not RabbitMQService._is_shutdown:
|
|
155
|
+
if asyncio.get_event_loop().time() - start_time > 30:
|
|
156
|
+
raise TimeoutError("RabbitMQ连接池初始化超时")
|
|
157
|
+
logging.info("等待RabbitMQ连接池初始化...")
|
|
158
|
+
await asyncio.sleep(1)
|
|
159
|
+
|
|
146
160
|
# 设置发送器,传递是否有监听器的标志
|
|
147
161
|
if rabbitmq_senders:
|
|
148
162
|
# 判断是否有监听器,如果有遍历监听器列表,队列名一样将prefetch_count属性设置到发送器对象中
|
|
@@ -159,20 +173,25 @@ class Services(metaclass=SingletonMeta):
|
|
|
159
173
|
|
|
160
174
|
# 验证初始化结果
|
|
161
175
|
if has_listeners:
|
|
176
|
+
# 异步获取客户端数量(适配新的RabbitMQService)
|
|
162
177
|
listener_count = len(RabbitMQService._clients)
|
|
163
178
|
logging.info(f"监听器初始化完成,共启动 {listener_count} 个消费者")
|
|
164
179
|
if listener_count == 0:
|
|
165
180
|
logging.warning("未成功初始化任何监听器,请检查配置")
|
|
166
181
|
|
|
167
182
|
async def _setup_senders_async(self, rabbitmq_senders, has_listeners: bool):
|
|
183
|
+
"""设置发送器(适配新的RabbitMQService异步方法)"""
|
|
168
184
|
Services._registered_senders = [
|
|
169
185
|
sender.queue_name for sender in rabbitmq_senders]
|
|
170
186
|
|
|
171
|
-
# 将是否有监听器的信息传递给RabbitMQService
|
|
187
|
+
# 将是否有监听器的信息传递给RabbitMQService(异步调用)
|
|
172
188
|
await RabbitMQService.setup_senders(rabbitmq_senders, has_listeners)
|
|
189
|
+
# 更新已注册的发送器(从RabbitMQService获取实际注册的名称)
|
|
190
|
+
Services._registered_senders = RabbitMQService._sender_client_names
|
|
173
191
|
logging.info(f"已注册的RabbitMQ发送器: {Services._registered_senders}")
|
|
174
192
|
|
|
175
193
|
async def _setup_listeners_async(self, rabbitmq_listeners, has_senders: bool):
|
|
194
|
+
"""设置监听器(适配新的RabbitMQService异步方法)"""
|
|
176
195
|
await RabbitMQService.setup_listeners(rabbitmq_listeners, has_senders)
|
|
177
196
|
|
|
178
197
|
@classmethod
|
|
@@ -183,23 +202,30 @@ class Services(metaclass=SingletonMeta):
|
|
|
183
202
|
max_retries: int = 3,
|
|
184
203
|
retry_delay: float = 1.0, **kwargs
|
|
185
204
|
) -> None:
|
|
186
|
-
"""
|
|
205
|
+
"""发送消息,添加重试机制(适配新的RabbitMQService异步API)"""
|
|
187
206
|
if not cls._initialized or not cls._loop:
|
|
188
207
|
logging.error("Services not properly initialized!")
|
|
189
208
|
raise ValueError("服务未正确初始化")
|
|
190
209
|
|
|
210
|
+
if RabbitMQService._is_shutdown:
|
|
211
|
+
logging.error("RabbitMQService已关闭,无法发送消息")
|
|
212
|
+
raise RuntimeError("RabbitMQ服务已关闭")
|
|
213
|
+
|
|
191
214
|
for attempt in range(max_retries):
|
|
192
215
|
try:
|
|
216
|
+
# 验证发送器是否注册
|
|
193
217
|
if queue_name not in cls._registered_senders:
|
|
194
218
|
cls._registered_senders = RabbitMQService._sender_client_names
|
|
195
219
|
if queue_name not in cls._registered_senders:
|
|
196
220
|
raise ValueError(f"发送器 {queue_name} 未注册")
|
|
197
221
|
|
|
198
|
-
|
|
222
|
+
# 获取发送器(适配新的异步get_sender方法)
|
|
223
|
+
sender = await RabbitMQService.get_sender(queue_name)
|
|
199
224
|
if not sender:
|
|
200
|
-
raise ValueError(f"发送器 '{queue_name}'
|
|
225
|
+
raise ValueError(f"发送器 '{queue_name}' 不存在或连接无效")
|
|
201
226
|
|
|
202
|
-
|
|
227
|
+
# 发送消息(调用RabbitMQService的异步send_message)
|
|
228
|
+
await RabbitMQService.send_message(data, queue_name, **kwargs)
|
|
203
229
|
logging.info(f"消息发送成功(尝试 {attempt+1}/{max_retries})")
|
|
204
230
|
return
|
|
205
231
|
|
|
@@ -215,17 +241,28 @@ class Services(metaclass=SingletonMeta):
|
|
|
215
241
|
)
|
|
216
242
|
await asyncio.sleep(retry_delay)
|
|
217
243
|
|
|
218
|
-
@
|
|
219
|
-
async def shutdown():
|
|
220
|
-
"""
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
244
|
+
@classmethod
|
|
245
|
+
async def shutdown(cls):
|
|
246
|
+
"""关闭所有服务(线程安全,适配新的RabbitMQService关闭逻辑)"""
|
|
247
|
+
async with cls._shutdown_lock:
|
|
248
|
+
if RabbitMQService._is_shutdown:
|
|
249
|
+
logging.info("RabbitMQService已关闭,无需重复操作")
|
|
250
|
+
return
|
|
251
|
+
|
|
252
|
+
# 取消所有MQ任务
|
|
253
|
+
for task in Services._mq_tasks:
|
|
254
|
+
if not task.done():
|
|
255
|
+
task.cancel()
|
|
256
|
+
try:
|
|
257
|
+
await task
|
|
258
|
+
except asyncio.CancelledError:
|
|
259
|
+
logging.info(f"MQ任务 {task.get_name()} 已取消")
|
|
260
|
+
|
|
261
|
+
# 关闭RabbitMQ服务(异步调用)
|
|
262
|
+
await RabbitMQService.shutdown()
|
|
263
|
+
|
|
264
|
+
# 清理全局状态
|
|
265
|
+
cls._initialized = False
|
|
266
|
+
cls._registered_senders.clear()
|
|
267
|
+
cls._mq_tasks.clear()
|
|
268
|
+
logging.info("所有服务已关闭")
|
sycommon/synacos/feign.py
CHANGED
|
@@ -97,7 +97,7 @@ async def feign(service_name, api_path, method='GET', params=None, headers=None,
|
|
|
97
97
|
data=data,
|
|
98
98
|
timeout=timeout
|
|
99
99
|
) as response:
|
|
100
|
-
return await _handle_feign_response(response)
|
|
100
|
+
return await _handle_feign_response(response, service_name, api_path)
|
|
101
101
|
else:
|
|
102
102
|
# 普通JSON请求
|
|
103
103
|
async with session.request(
|
|
@@ -108,30 +108,72 @@ async def feign(service_name, api_path, method='GET', params=None, headers=None,
|
|
|
108
108
|
json=body,
|
|
109
109
|
timeout=timeout
|
|
110
110
|
) as response:
|
|
111
|
-
return await _handle_feign_response(response)
|
|
111
|
+
return await _handle_feign_response(response, service_name, api_path)
|
|
112
112
|
except aiohttp.ClientError as e:
|
|
113
113
|
SYLogger.error(
|
|
114
|
-
f"nacos:请求服务接口时出错ClientError path: {api_path} error:{e}")
|
|
114
|
+
f"nacos:请求服务接口时出错ClientError server: {service_name} path: {api_path} error:{e}")
|
|
115
115
|
return None
|
|
116
116
|
except Exception as e:
|
|
117
117
|
import traceback
|
|
118
118
|
SYLogger.error(
|
|
119
|
-
f"nacos:请求服务接口时出错 path: {api_path} error:{traceback.format_exc()}")
|
|
119
|
+
f"nacos:请求服务接口时出错 server: {service_name} path: {api_path} error:{traceback.format_exc()}")
|
|
120
120
|
return None
|
|
121
121
|
finally:
|
|
122
122
|
await session.close()
|
|
123
123
|
|
|
124
124
|
|
|
125
|
-
async def _handle_feign_response(response):
|
|
126
|
-
"""
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
125
|
+
async def _handle_feign_response(response, service_name: str, api_path: str):
|
|
126
|
+
"""
|
|
127
|
+
处理Feign请求的响应,统一返回格式
|
|
128
|
+
调整逻辑:先判断状态码,再处理内容
|
|
129
|
+
- 200状态:优先识别JSON/文本,其他均按文件流(二进制)处理
|
|
130
|
+
- 非200状态:统一返回错误字典
|
|
131
|
+
"""
|
|
132
|
+
try:
|
|
133
|
+
status_code = response.status
|
|
134
|
+
content_type = response.headers.get('Content-Type', '').lower()
|
|
135
|
+
response_body = None
|
|
136
|
+
|
|
137
|
+
if status_code == 200:
|
|
138
|
+
if 'application/json' in content_type:
|
|
139
|
+
response_body = await response.json()
|
|
140
|
+
elif 'text/' in content_type:
|
|
141
|
+
# 文本类型(text/plain、text/html等):按文本读取
|
|
142
|
+
try:
|
|
143
|
+
response_body = await response.text(encoding='utf-8')
|
|
144
|
+
except UnicodeDecodeError:
|
|
145
|
+
# 兼容中文编码(gbk)
|
|
146
|
+
response_body = await response.text(encoding='gbk')
|
|
147
|
+
else:
|
|
148
|
+
# 其他类型(PDF、图片、octet-stream等):按文件流(二进制)读取
|
|
149
|
+
binary_data = await response.read()
|
|
150
|
+
SYLogger.info(
|
|
151
|
+
f"按文件流处理响应,类型:{content_type},大小:{len(binary_data)/1024:.2f}KB")
|
|
152
|
+
return io.BytesIO(binary_data) # 返回BytesIO,支持read()
|
|
153
|
+
return response_body
|
|
131
154
|
else:
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
155
|
+
# 非200状态:统一读取响应体(兼容文本/二进制错误信息)
|
|
156
|
+
try:
|
|
157
|
+
if 'application/json' in content_type:
|
|
158
|
+
response_body = await response.json()
|
|
159
|
+
else:
|
|
160
|
+
response_body = await response.text(encoding='utf-8', errors='ignore')
|
|
161
|
+
except Exception:
|
|
162
|
+
binary_data = await response.read()
|
|
163
|
+
response_body = f"非200状态,响应无法解码:{binary_data[:100].hex()} server: {service_name} path: {api_path}"
|
|
164
|
+
|
|
165
|
+
error_msg = f"请求失败,状态码: {status_code},响应内容: {str(response_body)[:500]} server: {service_name} path: {api_path}"
|
|
166
|
+
SYLogger.error(error_msg)
|
|
167
|
+
return {
|
|
168
|
+
"success": False,
|
|
169
|
+
"code": status_code,
|
|
170
|
+
"message": error_msg,
|
|
171
|
+
"data": response_body
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
except Exception as e:
|
|
175
|
+
import traceback
|
|
176
|
+
error_detail = f"处理响应异常: {str(e)}\n{traceback.format_exc()}"
|
|
177
|
+
SYLogger.error(
|
|
178
|
+
f"nacos:处理响应时出错: {error_detail} server: {service_name} path: {api_path}")
|
|
137
179
|
return None
|
|
@@ -10,7 +10,6 @@ import yaml
|
|
|
10
10
|
import time
|
|
11
11
|
import atexit
|
|
12
12
|
import random
|
|
13
|
-
from concurrent.futures import ThreadPoolExecutor
|
|
14
13
|
|
|
15
14
|
from sycommon.config.Config import SingletonMeta
|
|
16
15
|
from sycommon.logging.kafka_log import SYLogger
|
|
@@ -34,22 +33,17 @@ class NacosService(metaclass=SingletonMeta):
|
|
|
34
33
|
# 添加可重入锁用于状态同步
|
|
35
34
|
self._state_lock = threading.RLock()
|
|
36
35
|
|
|
37
|
-
# 优化线程池配置,增加工作线程数量
|
|
38
|
-
self._executor = ThreadPoolExecutor(max_workers=1) # 主线程池
|
|
39
|
-
self._heartbeat_executor = ThreadPoolExecutor(
|
|
40
|
-
max_workers=1) # 增加心跳线程
|
|
41
|
-
self._monitor_executor = ThreadPoolExecutor(
|
|
42
|
-
max_workers=1) # 增加监控线程
|
|
43
|
-
|
|
44
36
|
# 配置参数
|
|
45
37
|
self.max_retries = self.nacos_config.get('maxRetries', 5)
|
|
46
|
-
self.retry_delay = self.nacos_config.get('retryDelay',
|
|
47
|
-
self.retry_backoff = self.nacos_config.get('retryBackoff', 1.5)
|
|
38
|
+
self.retry_delay = self.nacos_config.get('retryDelay', 5)
|
|
48
39
|
self.max_retry_delay = self.nacos_config.get('maxRetryDelay', 30)
|
|
40
|
+
# 心跳间隔:优先从配置读取,默认15秒(可通过配置修改)
|
|
49
41
|
self.heartbeat_interval = self.nacos_config.get(
|
|
50
|
-
'heartbeatInterval',
|
|
42
|
+
'heartbeatInterval', 15)
|
|
43
|
+
# 心跳超时:固定设置为10秒(需求指定)
|
|
44
|
+
self.heartbeat_timeout = 15
|
|
51
45
|
self.register_retry_interval = self.nacos_config.get(
|
|
52
|
-
'registerRetryInterval',
|
|
46
|
+
'registerRetryInterval', 15) # 注册重试间隔
|
|
53
47
|
|
|
54
48
|
# 长期重试配置
|
|
55
49
|
self.long_term_retry_delay = self.nacos_config.get(
|
|
@@ -57,11 +51,13 @@ class NacosService(metaclass=SingletonMeta):
|
|
|
57
51
|
self.max_long_term_retries = self.nacos_config.get(
|
|
58
52
|
'maxLongTermRetries', -1) # -1表示无限重试
|
|
59
53
|
|
|
60
|
-
#
|
|
54
|
+
# 注册验证配置:优化默认值(增加次数+延长间隔)
|
|
61
55
|
self.registration_verify_count = self.nacos_config.get(
|
|
62
56
|
'registrationVerifyCount', 1) # 验证次数
|
|
63
57
|
self.registration_verify_interval = self.nacos_config.get(
|
|
64
58
|
'registrationVerifyInterval', 1) # 验证间隔
|
|
59
|
+
self.registration_post_delay = self.nacos_config.get(
|
|
60
|
+
'registrationPostDelay', 3) # 注册后延迟3秒再开始验证
|
|
65
61
|
|
|
66
62
|
self.real_ip = self.get_service_ip(self.host)
|
|
67
63
|
self._long_term_retry_count = 0 # 长期重试计数器
|
|
@@ -129,8 +125,7 @@ class NacosService(metaclass=SingletonMeta):
|
|
|
129
125
|
self._client_initialized = True
|
|
130
126
|
return True
|
|
131
127
|
except Exception as e:
|
|
132
|
-
delay = min(self.retry_delay
|
|
133
|
-
attempt), self.max_retry_delay)
|
|
128
|
+
delay = min(self.retry_delay, self.max_retry_delay)
|
|
134
129
|
SYLogger.error(
|
|
135
130
|
f"nacos:客户端初始化失败 (尝试 {attempt+1}/{self.max_retries}): {e}")
|
|
136
131
|
time.sleep(delay)
|
|
@@ -193,8 +188,7 @@ class NacosService(metaclass=SingletonMeta):
|
|
|
193
188
|
|
|
194
189
|
except Exception as e:
|
|
195
190
|
attempt += 1
|
|
196
|
-
delay = min(self.retry_delay
|
|
197
|
-
(attempt - 1)), self.max_retry_delay)
|
|
191
|
+
delay = min(self.retry_delay, self.max_retry_delay)
|
|
198
192
|
|
|
199
193
|
SYLogger.error(
|
|
200
194
|
f"nacos:客户端初始化失败 (尝试 {attempt}/{max_attempts}): {e}")
|
|
@@ -308,12 +302,12 @@ class NacosService(metaclass=SingletonMeta):
|
|
|
308
302
|
if not register_success:
|
|
309
303
|
raise RuntimeError("nacos:服务注册请求失败")
|
|
310
304
|
|
|
311
|
-
#
|
|
305
|
+
# 关键优化1:注册请求发送后,延迟一段时间再验证(默认3秒)
|
|
312
306
|
SYLogger.info(
|
|
313
|
-
f"nacos
|
|
314
|
-
time.sleep(self.
|
|
307
|
+
f"nacos:服务注册请求已发送,延迟 {self.registration_post_delay} 秒后开始验证(确保Nacos服务器完成实例写入)")
|
|
308
|
+
time.sleep(self.registration_post_delay)
|
|
315
309
|
|
|
316
|
-
#
|
|
310
|
+
# 关键优化2:多次验证服务是否真正注册成功(默认3次,每次间隔2秒)
|
|
317
311
|
registered = self.verify_registration()
|
|
318
312
|
|
|
319
313
|
# 带锁更新注册状态
|
|
@@ -342,8 +336,7 @@ class NacosService(metaclass=SingletonMeta):
|
|
|
342
336
|
except Exception as e:
|
|
343
337
|
last_error = str(e)
|
|
344
338
|
retry_count += 1
|
|
345
|
-
delay = min(self.register_retry_interval
|
|
346
|
-
(self.retry_backoff ** (retry_count - 1)), self.max_retry_delay)
|
|
339
|
+
delay = min(self.register_retry_interval, self.max_retry_delay)
|
|
347
340
|
|
|
348
341
|
SYLogger.warning(
|
|
349
342
|
f"nacos:服务注册尝试 {retry_count} 失败: {last_error},{delay}秒后重试")
|
|
@@ -429,8 +422,13 @@ class NacosService(metaclass=SingletonMeta):
|
|
|
429
422
|
timeout = 60 # 60秒超时
|
|
430
423
|
start_time = time.time()
|
|
431
424
|
|
|
432
|
-
#
|
|
433
|
-
|
|
425
|
+
# 启动注册线程,不阻塞主线程(替换原线程池)
|
|
426
|
+
register_thread = threading.Thread(
|
|
427
|
+
target=instance.register_with_retry,
|
|
428
|
+
daemon=True,
|
|
429
|
+
name="NacosRegisterThread"
|
|
430
|
+
)
|
|
431
|
+
register_thread.start()
|
|
434
432
|
|
|
435
433
|
# 等待注册完成或超时
|
|
436
434
|
while True:
|
|
@@ -461,7 +459,7 @@ class NacosService(metaclass=SingletonMeta):
|
|
|
461
459
|
|
|
462
460
|
# 启动连接监控线程
|
|
463
461
|
threading.Thread(target=instance.monitor_connection,
|
|
464
|
-
daemon=True).start()
|
|
462
|
+
daemon=True, name="NacosConnectionMonitorThread").start()
|
|
465
463
|
else:
|
|
466
464
|
SYLogger.info("nacos:本地开发模式,跳过服务注册流程")
|
|
467
465
|
|
|
@@ -485,7 +483,11 @@ class NacosService(metaclass=SingletonMeta):
|
|
|
485
483
|
)
|
|
486
484
|
self._heartbeat_thread.daemon = True
|
|
487
485
|
self._heartbeat_thread.start()
|
|
488
|
-
SYLogger.info(
|
|
486
|
+
SYLogger.info(
|
|
487
|
+
f"nacos:心跳线程启动,线程ID: {self._heartbeat_thread.ident},"
|
|
488
|
+
f"心跳间隔: {self.heartbeat_interval}秒,"
|
|
489
|
+
f"心跳超时: {self.heartbeat_timeout}秒"
|
|
490
|
+
)
|
|
489
491
|
|
|
490
492
|
def _send_heartbeat_loop(self):
|
|
491
493
|
"""优化后的心跳发送循环,确保严格按间隔执行"""
|
|
@@ -493,7 +495,8 @@ class NacosService(metaclass=SingletonMeta):
|
|
|
493
495
|
thread_ident = current_thread.ident
|
|
494
496
|
SYLogger.info(
|
|
495
497
|
f"nacos:心跳循环启动 - 线程ID: {thread_ident}, "
|
|
496
|
-
f"配置间隔: {self.heartbeat_interval}
|
|
498
|
+
f"配置间隔: {self.heartbeat_interval}秒, "
|
|
499
|
+
f"超时时间: {self.heartbeat_timeout}秒"
|
|
497
500
|
)
|
|
498
501
|
|
|
499
502
|
consecutive_fail = 0 # 连续失败计数器
|
|
@@ -512,7 +515,7 @@ class NacosService(metaclass=SingletonMeta):
|
|
|
512
515
|
f"nacos:服务未注册,跳过心跳 - 线程ID: {thread_ident}")
|
|
513
516
|
consecutive_fail = 0
|
|
514
517
|
else:
|
|
515
|
-
#
|
|
518
|
+
# 发送心跳(10秒超时)
|
|
516
519
|
success = self.send_heartbeat()
|
|
517
520
|
if success:
|
|
518
521
|
consecutive_fail = 0
|
|
@@ -545,26 +548,46 @@ class NacosService(metaclass=SingletonMeta):
|
|
|
545
548
|
SYLogger.info(f"nacos:心跳循环已停止 - 线程ID: {thread_ident}")
|
|
546
549
|
|
|
547
550
|
def send_heartbeat(self):
|
|
548
|
-
"""
|
|
551
|
+
"""发送心跳并添加10秒超时控制(替换线程池实现)"""
|
|
549
552
|
if not self.ensure_client_connected():
|
|
550
553
|
SYLogger.warning("nacos:客户端未连接,心跳发送失败")
|
|
551
554
|
return False
|
|
552
555
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
556
|
+
# 用线程+join实现10秒超时控制
|
|
557
|
+
result_list = [] # 用于线程间传递结果
|
|
558
|
+
|
|
559
|
+
def heartbeat_task():
|
|
560
|
+
"""心跳实际执行任务"""
|
|
561
|
+
try:
|
|
562
|
+
result = self._send_heartbeat_internal()
|
|
563
|
+
result_list.append(result)
|
|
564
|
+
except Exception as e:
|
|
565
|
+
SYLogger.error(f"nacos:心跳任务执行异常: {e}")
|
|
566
|
+
result_list.append(False)
|
|
567
|
+
|
|
568
|
+
# 启动心跳任务线程
|
|
569
|
+
task_thread = threading.Thread(
|
|
570
|
+
target=heartbeat_task,
|
|
571
|
+
daemon=True,
|
|
572
|
+
name="NacosHeartbeatTaskThread"
|
|
573
|
+
)
|
|
574
|
+
task_thread.start()
|
|
575
|
+
|
|
576
|
+
# 等待线程完成,最多等待10秒
|
|
577
|
+
task_thread.join(timeout=self.heartbeat_timeout)
|
|
578
|
+
|
|
579
|
+
# 处理结果
|
|
580
|
+
if not result_list:
|
|
581
|
+
# 超时未返回
|
|
582
|
+
SYLogger.error(f"nacos:心跳发送超时({self.heartbeat_timeout}秒)")
|
|
565
583
|
self._client_initialized = False # 强制重连
|
|
566
584
|
return False
|
|
567
585
|
|
|
586
|
+
# 检查心跳结果
|
|
587
|
+
if result_list[0]:
|
|
588
|
+
self._last_successful_heartbeat = time.time()
|
|
589
|
+
return result_list[0]
|
|
590
|
+
|
|
568
591
|
def _send_heartbeat_internal(self):
|
|
569
592
|
"""实际的心跳发送逻辑"""
|
|
570
593
|
result = self.nacos_client.send_heartbeat(
|
|
@@ -620,9 +643,13 @@ class NacosService(metaclass=SingletonMeta):
|
|
|
620
643
|
else:
|
|
621
644
|
self.registered = False
|
|
622
645
|
SYLogger.warning(f"nacos:服务实例未注册,尝试重新注册")
|
|
623
|
-
#
|
|
624
|
-
|
|
625
|
-
self.register_with_retry
|
|
646
|
+
# 启动临时线程执行重新注册(替换原线程池)
|
|
647
|
+
retry_thread = threading.Thread(
|
|
648
|
+
target=self.register_with_retry,
|
|
649
|
+
daemon=True,
|
|
650
|
+
name="NacosRetryRegisterThread"
|
|
651
|
+
)
|
|
652
|
+
retry_thread.start()
|
|
626
653
|
|
|
627
654
|
# 20%的概率执行深度检查
|
|
628
655
|
if random.random() < 0.2:
|
|
@@ -673,13 +700,6 @@ class NacosService(metaclass=SingletonMeta):
|
|
|
673
700
|
SYLogger.error(f"nacos:注销服务时发生错误: {e}")
|
|
674
701
|
finally:
|
|
675
702
|
self._shutdown_event.set()
|
|
676
|
-
# 优雅地关闭线程池
|
|
677
|
-
if self._executor and not self._executor._shutdown:
|
|
678
|
-
self._executor.shutdown(wait=True)
|
|
679
|
-
if self._heartbeat_executor and not self._heartbeat_executor._shutdown:
|
|
680
|
-
self._heartbeat_executor.shutdown(wait=True)
|
|
681
|
-
if self._monitor_executor and not self._monitor_executor._shutdown:
|
|
682
|
-
self._monitor_executor.shutdown(wait=True)
|
|
683
703
|
|
|
684
704
|
def handle_signal(self, signum, frame):
|
|
685
705
|
"""处理退出信号"""
|
|
@@ -751,7 +771,8 @@ class NacosService(metaclass=SingletonMeta):
|
|
|
751
771
|
for data_id, callback in list(self._config_listeners.items()):
|
|
752
772
|
new_config = self.get_config(data_id)
|
|
753
773
|
if new_config and new_config != self._config_cache.get(data_id):
|
|
754
|
-
|
|
774
|
+
# 直接执行回调(替换原线程池,配置回调通常为轻量操作)
|
|
775
|
+
callback(new_config)
|
|
755
776
|
self._config_cache[data_id] = new_config
|
|
756
777
|
except Exception as e:
|
|
757
778
|
SYLogger.error(f"nacos:配置监视线程异常: {str(e)}")
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sycommon-python-lib
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.46
|
|
4
4
|
Summary: Add your description here
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
7
|
-
Requires-Dist: aio-pika>=9.5.
|
|
8
|
-
Requires-Dist: aiohttp>=3.13.
|
|
7
|
+
Requires-Dist: aio-pika>=9.5.8
|
|
8
|
+
Requires-Dist: aiohttp>=3.13.2
|
|
9
9
|
Requires-Dist: decorator>=5.2.1
|
|
10
|
-
Requires-Dist: fastapi>=0.
|
|
11
|
-
Requires-Dist: kafka-python>=2.2.
|
|
10
|
+
Requires-Dist: fastapi>=0.121.2
|
|
11
|
+
Requires-Dist: kafka-python>=2.2.16
|
|
12
12
|
Requires-Dist: loguru>=0.7.3
|
|
13
13
|
Requires-Dist: mysql-connector-python>=9.5.0
|
|
14
14
|
Requires-Dist: nacos-sdk-python>=2.0.9
|
|
15
|
-
Requires-Dist: pydantic>=2.12.
|
|
15
|
+
Requires-Dist: pydantic>=2.12.4
|
|
16
16
|
Requires-Dist: python-dotenv>=1.2.1
|
|
17
17
|
Requires-Dist: pyyaml>=6.0.3
|
|
18
18
|
Requires-Dist: sqlalchemy>=2.0.44
|
|
19
|
-
Requires-Dist: starlette>=0.
|
|
19
|
+
Requires-Dist: starlette>=0.49.3
|
|
20
20
|
Requires-Dist: uuid>=1.30
|
|
21
21
|
Requires-Dist: uvicorn>=0.38.0
|
|
22
22
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
command/cli.py,sha256=bP2LCLkRvfETIwWkVD70q5xFxMI4D3BpH09Ws1f-ENc,5849
|
|
2
2
|
sycommon/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
sycommon/services.py,sha256=
|
|
3
|
+
sycommon/services.py,sha256=LHMRxxRvLAiekkVspaQClBgAR_jLKqiJpd5hqF74MIE,11369
|
|
4
4
|
sycommon/config/Config.py,sha256=9yO5b8WfvEDvkyrGrlwrLFasgh_-MjcEvGF20Gz5Xo4,3041
|
|
5
5
|
sycommon/config/DatabaseConfig.py,sha256=ILiUuYT9_xJZE2W-RYuC3JCt_YLKc1sbH13-MHIOPhg,804
|
|
6
6
|
sycommon/config/EmbeddingConfig.py,sha256=gPKwiDYbeu1GpdIZXMmgqM7JqBIzCXi0yYuGRLZooMI,362
|
|
@@ -27,7 +27,7 @@ sycommon/middleware/middleware.py,sha256=SzZ4wufSNdwC4Ppw99TE7a6AVGkrZRc55NHSrA3
|
|
|
27
27
|
sycommon/middleware/monitor_memory.py,sha256=pYRK-wRuDd6enSg9Pf8tQxPdYQS6S0AyjyXeKFRLKEs,628
|
|
28
28
|
sycommon/middleware/mq.py,sha256=4wBqiT5wJGcrfjk2GSr0_U3TStBxoNpHTzcRxVlMEHE,183
|
|
29
29
|
sycommon/middleware/timeout.py,sha256=fImlAPLm4Oa8N9goXtT_0os1GZPCi9F92OgXU81DgDU,656
|
|
30
|
-
sycommon/middleware/traceid.py,sha256=
|
|
30
|
+
sycommon/middleware/traceid.py,sha256=ugqPgHdUydj7m481rM_RH-yrIK9hAdkLemdPSSOnQvw,6821
|
|
31
31
|
sycommon/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
32
32
|
sycommon/models/base_http.py,sha256=EICAAibx3xhjBsLqm35Mi3DCqxp0FME4rD_3iQVjT_E,3051
|
|
33
33
|
sycommon/models/log.py,sha256=rZpj6VkDRxK3B6H7XSeWdYZshU8F0Sks8bq1p6pPlDw,500
|
|
@@ -35,25 +35,25 @@ sycommon/models/mqlistener_config.py,sha256=vXp2uMmd0XQ5B9noSRXWHewTy-juQ2y7IsWt
|
|
|
35
35
|
sycommon/models/mqmsg_model.py,sha256=cxn0M5b0utQK6crMYmL-1waeGYHvK3AlGaRy23clqTE,277
|
|
36
36
|
sycommon/models/mqsend_config.py,sha256=NQX9dc8PpuquMG36GCVhJe8omAW1KVXXqr6lSRU6D7I,268
|
|
37
37
|
sycommon/models/sso_user.py,sha256=i1WAN6k5sPcPApQEdtjpWDy7VrzWLpOrOQewGLGoGIw,2702
|
|
38
|
-
sycommon/rabbitmq/rabbitmq_client.py,sha256=
|
|
39
|
-
sycommon/rabbitmq/rabbitmq_pool.py,sha256=
|
|
40
|
-
sycommon/rabbitmq/rabbitmq_service.py,sha256=
|
|
38
|
+
sycommon/rabbitmq/rabbitmq_client.py,sha256=dKpiptV892VbW3fErAoRZSE9UVVBZvbVPM3qPu8rQIk,21573
|
|
39
|
+
sycommon/rabbitmq/rabbitmq_pool.py,sha256=VLJ6JIIoVf1_NKV7FNmDFVkX5klN2JtLzbuUaaroEdc,27096
|
|
40
|
+
sycommon/rabbitmq/rabbitmq_service.py,sha256=UUvGkmDBQ7xTdCLYqkDSYZw5-FUNU7vnmgmANh4Z_bI,39960
|
|
41
41
|
sycommon/sse/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
42
|
sycommon/sse/event.py,sha256=k_rBJy23R7crtzQeetT0Q73D8o5-5p-eESGSs_BPOj0,2797
|
|
43
43
|
sycommon/sse/sse.py,sha256=__CfWEcYxOxQ-HpLor4LTZ5hLWqw9-2X7CngqbVHsfw,10128
|
|
44
44
|
sycommon/synacos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
45
|
sycommon/synacos/example.py,sha256=61XL03tU8WTNOo3FUduf93F2fAwah1S0lbH1ufhRhRk,5739
|
|
46
46
|
sycommon/synacos/example2.py,sha256=adUaru3Hy482KrOA17DfaC4nwvLj8etIDS_KrWLWmCU,4811
|
|
47
|
-
sycommon/synacos/feign.py,sha256
|
|
47
|
+
sycommon/synacos/feign.py,sha256=-2tuGCqoSM3ddSoSz7h1RJTB06hn8K26v_1ev4qLsTU,7728
|
|
48
48
|
sycommon/synacos/feign_client.py,sha256=JxzxohrsscQNlAjRVo_3ZQrMQSfVHFOtRYyEnP6sDGk,15205
|
|
49
|
-
sycommon/synacos/nacos_service.py,sha256=
|
|
49
|
+
sycommon/synacos/nacos_service.py,sha256=2m1ZxIii3r657kQJfp7C7I5bxBUEGDweYMfloUUmBSw,35389
|
|
50
50
|
sycommon/synacos/param.py,sha256=KcfSkxnXOa0TGmCjY8hdzU9pzUsA8-4PeyBKWI2-568,1765
|
|
51
51
|
sycommon/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
52
52
|
sycommon/tools/docs.py,sha256=OPj2ETheuWjXLyaXtaZPbwmJKfJaYXV5s4XMVAUNrms,1607
|
|
53
53
|
sycommon/tools/snowflake.py,sha256=DdEj3T5r5OEvikp3puxqmmmz6BrggxomoSlnsRFb5dM,1174
|
|
54
54
|
sycommon/tools/timing.py,sha256=OiiE7P07lRoMzX9kzb8sZU9cDb0zNnqIlY5pWqHcnkY,2064
|
|
55
|
-
sycommon_python_lib-0.1.
|
|
56
|
-
sycommon_python_lib-0.1.
|
|
57
|
-
sycommon_python_lib-0.1.
|
|
58
|
-
sycommon_python_lib-0.1.
|
|
59
|
-
sycommon_python_lib-0.1.
|
|
55
|
+
sycommon_python_lib-0.1.46.dist-info/METADATA,sha256=TAAHgjLYJMlud71VM9Q_Fe98-3cNO9Gj2-mgUXmUWPI,7037
|
|
56
|
+
sycommon_python_lib-0.1.46.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
57
|
+
sycommon_python_lib-0.1.46.dist-info/entry_points.txt,sha256=q_h2nbvhhmdnsOUZEIwpuoDjaNfBF9XqppDEmQn9d_A,46
|
|
58
|
+
sycommon_python_lib-0.1.46.dist-info/top_level.txt,sha256=98CJ-cyM2WIKxLz-Pf0AitWLhJyrfXvyY8slwjTXNuc,17
|
|
59
|
+
sycommon_python_lib-0.1.46.dist-info/RECORD,,
|
|
File without changes
|
{sycommon_python_lib-0.1.32.dist-info → sycommon_python_lib-0.1.46.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|