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