codosdk 1.0.42__tar.gz → 1.0.44__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.
Files changed (52) hide show
  1. {codosdk-1.0.42 → codosdk-1.0.44}/PKG-INFO +1 -1
  2. {codosdk-1.0.42 → codosdk-1.0.44}/codosdk.egg-info/PKG-INFO +1 -1
  3. {codosdk-1.0.42 → codosdk-1.0.44}/setup.py +1 -1
  4. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/mqhelper.py +90 -53
  5. {codosdk-1.0.42 → codosdk-1.0.44}/LICENSE +0 -0
  6. {codosdk-1.0.42 → codosdk-1.0.44}/README.md +0 -0
  7. {codosdk-1.0.42 → codosdk-1.0.44}/codosdk.egg-info/SOURCES.txt +0 -0
  8. {codosdk-1.0.42 → codosdk-1.0.44}/codosdk.egg-info/dependency_links.txt +0 -0
  9. {codosdk-1.0.42 → codosdk-1.0.44}/codosdk.egg-info/requires.txt +0 -0
  10. {codosdk-1.0.42 → codosdk-1.0.44}/codosdk.egg-info/top_level.txt +0 -0
  11. {codosdk-1.0.42 → codosdk-1.0.44}/opssdk/__init__.py +0 -0
  12. {codosdk-1.0.42 → codosdk-1.0.44}/opssdk/utils/__init__.py +0 -0
  13. {codosdk-1.0.42 → codosdk-1.0.44}/pyproject.toml +0 -0
  14. {codosdk-1.0.42 → codosdk-1.0.44}/setup.cfg +0 -0
  15. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/__init__.py +0 -0
  16. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/api_set.py +0 -0
  17. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/apis/__init__.py +0 -0
  18. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/apis/admin_apis.py +0 -0
  19. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/apis/agent_apis.py +0 -0
  20. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/apis/cmdb_apis.py +0 -0
  21. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/apis/kerrigan_apis.py +0 -0
  22. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/apis/mgv4_apis.py +0 -0
  23. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/apis/notice_apis.py +0 -0
  24. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/apis/task_apis.py +0 -0
  25. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/application.py +0 -0
  26. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/base_handler.py +0 -0
  27. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/cache.py +0 -0
  28. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/cache_context.py +0 -0
  29. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/client.py +0 -0
  30. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/cloud/__init__.py +0 -0
  31. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/cloud/qcloud_api.py +0 -0
  32. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/cloud/ucloud_api.py +0 -0
  33. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/cloud_utils.py +0 -0
  34. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/configs.py +0 -0
  35. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/consts.py +0 -0
  36. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/crud_utils.py +0 -0
  37. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/db_context.py +0 -0
  38. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/error.py +0 -0
  39. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/fetch_coroutine.py +0 -0
  40. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/jwt_token.py +0 -0
  41. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/ldap.py +0 -0
  42. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/logger.py +0 -0
  43. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/model_utils.py +0 -0
  44. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/program.py +0 -0
  45. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/salt_api.py +0 -0
  46. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/sqlalchemy_pagination.py +0 -0
  47. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/tools.py +0 -0
  48. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/utils/__init__.py +0 -0
  49. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/utils/cc_crypto.py +0 -0
  50. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/utils/date_format.py +0 -0
  51. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/utils/pydantic_utils.py +0 -0
  52. {codosdk-1.0.42 → codosdk-1.0.44}/websdk2/web_logs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codosdk
3
- Version: 1.0.42
3
+ Version: 1.0.44
4
4
  Summary: CODO项目的Python SDK
5
5
  Home-page: https://github.com/ss1917/codo_sdk/
6
6
  Author: shenshuo
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codosdk
3
- Version: 1.0.42
3
+ Version: 1.0.44
4
4
  Summary: CODO项目的Python SDK
5
5
  Home-page: https://github.com/ss1917/codo_sdk/
6
6
  Author: shenshuo
@@ -9,7 +9,7 @@ desc : CODO SDK
9
9
  import sys
10
10
  from setuptools import setup, find_packages
11
11
 
12
- VERSION = '1.0.42'
12
+ VERSION = '1.0.44'
13
13
 
14
14
  if sys.version_info < (2, 7) or (3, 0) <= sys.version_info < (3, 6):
15
15
  print('This program requires at least Python 2.7 or 3.6 to run.')
@@ -9,6 +9,7 @@ role : rabbitMQ 操作类
9
9
  import logging
10
10
  import traceback
11
11
  import pika
12
+ import time
12
13
  import threading
13
14
  from typing import Optional, List, Dict, Any, Callable
14
15
  from .consts import const
@@ -120,7 +121,6 @@ logger.setLevel(logging.WARNING)
120
121
  # else:
121
122
  # self.__channel.basic_publish(exchange=self.__exchange, routing_key=self.__routing_key, body=body)
122
123
  # logging.info('Publish message %s sucessfuled.' % body)
123
-
124
124
  class RabbitMQConnectionPool:
125
125
  """RabbitMQ连接池管理器 - 实现一个应用一个连接的最佳实践"""
126
126
 
@@ -165,13 +165,7 @@ class RabbitMQConnectionPool:
165
165
  socket_timeout=30, # 添加socket超时
166
166
  connection_attempts=3, # 连接重试次数
167
167
  retry_delay=1, # 重试延迟
168
- stack_timeout=30, # 栈超时
169
- # 添加TCP连接参数 某些系统上可能不被支持 删除
170
- # tcp_options={
171
- # 'TCP_KEEPIDLE': 60,
172
- # 'TCP_KEEPINTVL': 30,
173
- # 'TCP_KEEPCNT': 3
174
- # }
168
+ stack_timeout=30 # 栈超时
175
169
  )
176
170
 
177
171
  connection = pika.BlockingConnection(connection_params)
@@ -270,52 +264,87 @@ class MessageQueueBase:
270
264
  f"you must provide a queue_name to avoid anonymous queues."
271
265
  )
272
266
 
273
- # def _get_channel(self) -> Any:
274
- # """获取新的通道"""
275
- # connection = RabbitMQConnectionPool.get_connection(self._mq_key)
276
- # return connection.channel()
277
-
278
267
  def _get_channel(self) -> Any:
279
- """获取新的通道"""
280
- max_attempts = 3
268
+ """获取新的通道 - 使用更安全的方式避免pika并发Bug"""
269
+ max_attempts = 2 # 减少重试次数避免过度重试
270
+
281
271
  for attempt in range(max_attempts):
282
272
  try:
273
+ # 每次都创建新连接,避免连接复用导致的并发问题
274
+ if attempt > 0:
275
+ # 强制清理并等待
276
+ with RabbitMQConnectionPool._connection_lock:
277
+ try:
278
+ if self._mq_key in RabbitMQConnectionPool._connections:
279
+ RabbitMQConnectionPool._cleanup_connection(self._mq_key)
280
+ RabbitMQConnectionPool._connections[self._mq_key] = None
281
+ except:
282
+ pass
283
+
284
+ # 等待稍长时间让连接完全清理
285
+ time.sleep(0.5)
286
+
283
287
  connection = RabbitMQConnectionPool.get_connection(self._mq_key)
284
- if not connection or not connection.is_open:
285
- raise Exception("Connection is not available or not open")
288
+ if not connection:
289
+ raise Exception("Failed to get connection")
286
290
 
287
- # 添加连接状态检查
288
- try:
289
- # 尝试发送心跳检查连接状态
290
- connection.process_data_events(time_limit=0)
291
- except:
292
- raise Exception("Connection heartbeat failed")
291
+ # 简化状态检查,避免触发pika内部Bug
292
+ if hasattr(connection, 'is_open') and not connection.is_open:
293
+ raise Exception("Connection is not open")
293
294
 
295
+ # 直接创建channel,不做额外的心跳检查
294
296
  channel = connection.channel()
295
- if not channel or not channel.is_open:
296
- raise Exception("Channel is not available or not open")
297
+ if not channel:
298
+ raise Exception("Failed to create channel")
299
+
300
+ if hasattr(channel, 'is_open') and not channel.is_open:
301
+ raise Exception("Channel is not open")
302
+
297
303
  return channel
298
304
 
299
305
  except Exception as e:
300
- self.logger.warning(f"Failed to get healthy channel (attempt {attempt + 1}): {e}")
301
- if attempt < max_attempts - 1:
302
- # 清理并重建连接
303
- with RabbitMQConnectionPool._connection_lock:
304
- try:
305
- RabbitMQConnectionPool._cleanup_connection(self._mq_key)
306
- RabbitMQConnectionPool._connections[self._mq_key] = None
307
- except Exception as cleanup_e:
308
- self.logger.warning(f"Error during connection cleanup: {cleanup_e}")
309
-
310
- # 短暂等待后重试
311
- import time
312
- time.sleep(0.1 * (attempt + 1))
313
- else:
314
- # 最后一次尝试失败,抛出异常
315
- raise Exception(f"Failed to get channel after {max_attempts} attempts: {e}")
306
+ self.logger.warning(f"Failed to get channel (attempt {attempt + 1}/{max_attempts}): {e}")
307
+ if attempt == max_attempts - 1:
308
+ # 最后一次失败,创建一个临时连接
309
+ try:
310
+ return self._create_emergency_channel()
311
+ except Exception as emergency_e:
312
+ raise Exception(f"All channel attempts failed. Last error: {e}, Emergency error: {emergency_e}")
313
+
314
+ raise Exception("Unexpected error in channel creation")
315
+
316
+ def _create_emergency_channel(self) -> Any:
317
+ """创建紧急通道 - 直接连接,不使用连接池"""
318
+ try:
319
+ mq_config = configs[const.MQ_CONFIG_ITEM][self._mq_key]
320
+
321
+ credentials = pika.PlainCredentials(
322
+ mq_config[const.MQ_USER],
323
+ mq_config[const.MQ_PWD]
324
+ )
325
+
326
+ # 使用最简单的连接参数
327
+ connection_params = pika.ConnectionParameters(
328
+ host=mq_config[const.MQ_ADDR],
329
+ port=int(mq_config[const.MQ_PORT]),
330
+ virtual_host=mq_config[const.MQ_VHOST],
331
+ credentials=credentials,
332
+ heartbeat=0, # 禁用心跳
333
+ socket_timeout=10
334
+ )
335
+
336
+ connection = pika.BlockingConnection(connection_params)
337
+ channel = connection.channel()
338
+
339
+ self.logger.info("Created emergency channel")
340
+ return channel
341
+
342
+ except Exception as e:
343
+ self.logger.error(f"Failed to create emergency channel: {e}")
344
+ raise
316
345
 
317
346
  def _with_retry(self, operation: Callable, *args, **kwargs) -> Any:
318
- """带重试机制执行操作"""
347
+ """带重试机制执行操作 - 优化版本"""
319
348
  last_exception = None
320
349
 
321
350
  for attempt in range(self._max_retries + 1):
@@ -333,7 +362,7 @@ class MessageQueueBase:
333
362
  error_str = str(e).lower()
334
363
  if any(keyword in error_str for keyword in [
335
364
  'connection', 'channel', 'socket', 'transport',
336
- 'callback', 'deque', 'abort', 'closed'
365
+ 'callback', 'deque', 'abort', 'closed', 'asynctransport'
337
366
  ]):
338
367
  # 安全地清理连接
339
368
  with RabbitMQConnectionPool._connection_lock:
@@ -344,9 +373,8 @@ class MessageQueueBase:
344
373
  except Exception as cleanup_e:
345
374
  self.logger.debug(f"Error during connection cleanup: {cleanup_e}")
346
375
 
347
- # 递增延迟重试
348
- import time
349
- time.sleep(0.1 * (2 ** attempt))
376
+ # 递增延迟重试,但不要太长
377
+ time.sleep(min(0.1 * (2 ** attempt), 2.0))
350
378
 
351
379
  raise last_exception
352
380
 
@@ -374,7 +402,7 @@ class MessageQueueBase:
374
402
 
375
403
  # 如果有队列名,声明并绑定队列
376
404
  if self._queue_name:
377
- channel.queue_declare(queue=self._queue_name)
405
+ channel.queue_declare(queue=self._queue_name, durable=True)
378
406
  channel.queue_bind(
379
407
  exchange=self._exchange,
380
408
  queue=self._queue_name,
@@ -394,8 +422,11 @@ class MessageQueueBase:
394
422
  f'Published message to exchange:{self._exchange}, routing_key:{actual_routing_key}')
395
423
 
396
424
  finally:
397
- if channel and channel.is_open:
398
- channel.close()
425
+ if channel and hasattr(channel, 'is_open') and channel.is_open:
426
+ try:
427
+ channel.close()
428
+ except:
429
+ pass # 忽略关闭时的错误
399
430
 
400
431
  self._with_retry(_publish_operation)
401
432
 
@@ -445,11 +476,17 @@ class MessageQueueBase:
445
476
 
446
477
  except KeyboardInterrupt:
447
478
  self.logger.info("Received interrupt signal, stopping consumption")
448
- if channel and channel.is_open:
449
- channel.stop_consuming()
479
+ if channel and hasattr(channel, 'is_open') and channel.is_open:
480
+ try:
481
+ channel.stop_consuming()
482
+ except:
483
+ pass
450
484
  finally:
451
- if channel and channel.is_open:
452
- channel.close()
485
+ if channel and hasattr(channel, 'is_open') and channel.is_open:
486
+ try:
487
+ channel.close()
488
+ except:
489
+ pass
453
490
 
454
491
  self._with_retry(_consume_operation)
455
492
 
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
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