sycommon-python-lib 0.2.0b16__tar.gz → 0.2.0b18__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 (128) hide show
  1. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/PKG-INFO +1 -1
  2. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/pyproject.toml +1 -1
  3. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/database/async_base_db_service.py +0 -6
  4. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/database/base_db_service.py +0 -6
  5. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/llm/get_llm.py +1 -1
  6. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/notice/uvicorn_monitor.py +160 -2
  7. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/rabbitmq/rabbitmq_pool.py +102 -2
  8. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/synacos/nacos_heartbeat_manager.py +73 -0
  9. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/synacos/nacos_service_discovery.py +54 -0
  10. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon_python_lib.egg-info/PKG-INFO +1 -1
  11. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/README.md +0 -0
  12. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/setup.cfg +0 -0
  13. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/command/__init__.py +0 -0
  14. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/command/cli.py +0 -0
  15. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/command/console.py +0 -0
  16. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/command/models.py +0 -0
  17. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/command/project.py +0 -0
  18. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/command/utils.py +0 -0
  19. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/__init__.py +0 -0
  20. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/__init__.py +0 -0
  21. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/01_basic_agent.py +0 -0
  22. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/02_tool_agent.py +0 -0
  23. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/03_structured_output.py +0 -0
  24. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/04_memory_agent.py +0 -0
  25. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/05_streaming.py +0 -0
  26. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/06_multi_agent.py +0 -0
  27. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/07_skills_agent.py +0 -0
  28. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/08_middleware.py +0 -0
  29. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/09_interrupt.py +0 -0
  30. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/10_custom_llm.py +0 -0
  31. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/11_complex_workflow.py +0 -0
  32. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/12_batch_processing.py +0 -0
  33. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/__init__.py +0 -0
  34. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/middleware/01_basic_monitoring.py +0 -0
  35. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/middleware/02_permission_control.py +0 -0
  36. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/middleware/03_tool_skill_filter.py +0 -0
  37. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/middleware/04_caching_retry.py +0 -0
  38. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/middleware/05_sanitization.py +0 -0
  39. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/middleware/06_tracking.py +0 -0
  40. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/middleware/07_advanced.py +0 -0
  41. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/middleware/08_progressive_skills.py +0 -0
  42. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/middleware/__init__.py +0 -0
  43. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/examples/middleware/override_examples.py +0 -0
  44. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/agent/get_agent.py +0 -0
  45. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/config/Config.py +0 -0
  46. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/config/DatabaseConfig.py +0 -0
  47. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/config/EmbeddingConfig.py +0 -0
  48. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/config/LLMConfig.py +0 -0
  49. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/config/LangfuseConfig.py +0 -0
  50. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/config/MQConfig.py +0 -0
  51. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/config/RerankerConfig.py +0 -0
  52. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/config/SentryConfig.py +0 -0
  53. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/config/__init__.py +0 -0
  54. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/database/async_database_service.py +0 -0
  55. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/database/database_service.py +0 -0
  56. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/health/__init__.py +0 -0
  57. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/health/health_check.py +0 -0
  58. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/health/metrics.py +0 -0
  59. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/health/ping.py +0 -0
  60. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/llm/__init__.py +0 -0
  61. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/llm/embedding.py +0 -0
  62. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/llm/llm_logger.py +0 -0
  63. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/llm/llm_tokens.py +0 -0
  64. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/llm/struct_token.py +0 -0
  65. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/llm/sy_langfuse.py +0 -0
  66. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/llm/usage_token.py +0 -0
  67. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/logging/__init__.py +0 -0
  68. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/logging/async_sql_logger.py +0 -0
  69. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/logging/kafka_log.py +0 -0
  70. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/logging/logger_levels.py +0 -0
  71. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/logging/logger_wrapper.py +0 -0
  72. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/logging/sql_logger.py +0 -0
  73. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/middleware/__init__.py +0 -0
  74. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/middleware/context.py +0 -0
  75. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/middleware/cors.py +0 -0
  76. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/middleware/docs.py +0 -0
  77. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/middleware/exception.py +0 -0
  78. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/middleware/middleware.py +0 -0
  79. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/middleware/monitor_memory.py +0 -0
  80. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/middleware/mq.py +0 -0
  81. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/middleware/timeout.py +0 -0
  82. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/middleware/traceid.py +0 -0
  83. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/models/__init__.py +0 -0
  84. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/models/base_http.py +0 -0
  85. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/models/log.py +0 -0
  86. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/models/mqlistener_config.py +0 -0
  87. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/models/mqmsg_model.py +0 -0
  88. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/models/mqsend_config.py +0 -0
  89. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/models/sso_user.py +0 -0
  90. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/notice/__init__.py +0 -0
  91. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/rabbitmq/rabbitmq_client.py +0 -0
  92. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/rabbitmq/rabbitmq_service.py +0 -0
  93. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/rabbitmq/rabbitmq_service_client_manager.py +0 -0
  94. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/rabbitmq/rabbitmq_service_connection_monitor.py +0 -0
  95. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/rabbitmq/rabbitmq_service_consumer_manager.py +0 -0
  96. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/rabbitmq/rabbitmq_service_core.py +0 -0
  97. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/rabbitmq/rabbitmq_service_producer_manager.py +0 -0
  98. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/sentry/__init__.py +0 -0
  99. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/sentry/sy_sentry.py +0 -0
  100. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/services.py +0 -0
  101. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/sse/__init__.py +0 -0
  102. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/sse/event.py +0 -0
  103. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/sse/sse.py +0 -0
  104. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/synacos/__init__.py +0 -0
  105. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/synacos/example.py +0 -0
  106. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/synacos/example2.py +0 -0
  107. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/synacos/feign.py +0 -0
  108. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/synacos/feign_client.py +0 -0
  109. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/synacos/nacos_client_base.py +0 -0
  110. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/synacos/nacos_config_manager.py +0 -0
  111. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/synacos/nacos_service.py +0 -0
  112. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/synacos/nacos_service_registration.py +0 -0
  113. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/synacos/param.py +0 -0
  114. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/tests/test_email.py +0 -0
  115. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/tests/test_mq.py +0 -0
  116. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/tools/__init__.py +0 -0
  117. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/tools/async_utils.py +0 -0
  118. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/tools/docs.py +0 -0
  119. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/tools/env.py +0 -0
  120. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/tools/merge_headers.py +0 -0
  121. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/tools/snowflake.py +0 -0
  122. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/tools/syemail.py +0 -0
  123. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon/tools/timing.py +0 -0
  124. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon_python_lib.egg-info/SOURCES.txt +0 -0
  125. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon_python_lib.egg-info/dependency_links.txt +0 -0
  126. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon_python_lib.egg-info/entry_points.txt +0 -0
  127. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon_python_lib.egg-info/requires.txt +0 -0
  128. {sycommon_python_lib-0.2.0b16 → sycommon_python_lib-0.2.0b18}/src/sycommon_python_lib.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sycommon-python-lib
3
- Version: 0.2.0b16
3
+ Version: 0.2.0b18
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sycommon-python-lib"
3
- version = "0.2.0b16"
3
+ version = "0.2.0b18"
4
4
  description = "Add your description here"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -8,13 +8,7 @@ from sycommon.logging.kafka_log import SYLogger
8
8
  class AsyncBaseDBService(metaclass=SingletonMeta):
9
9
  """数据库操作基础服务类,封装异步会话管理功能"""
10
10
 
11
- _initialized: bool = False
12
-
13
11
  def __init__(self):
14
- if AsyncBaseDBService._initialized:
15
- return
16
- AsyncBaseDBService._initialized = True
17
-
18
12
  # 获取异步引擎 (假设 DatabaseService.engine() 返回的是 AsyncEngine)
19
13
  self.engine = AsyncDatabaseService.engine()
20
14
 
@@ -8,13 +8,7 @@ from sycommon.logging.kafka_log import SYLogger
8
8
  class BaseDBService(metaclass=SingletonMeta):
9
9
  """数据库操作基础服务类,封装会话管理功能"""
10
10
 
11
- _initialized: bool = False
12
-
13
11
  def __init__(self):
14
- if BaseDBService._initialized:
15
- return
16
- BaseDBService._initialized = True
17
-
18
12
  self.engine = DatabaseService.engine()
19
13
  self.Session = sessionmaker(bind=self.engine)
20
14
 
@@ -62,7 +62,7 @@ def get_llm(
62
62
  )
63
63
  ```
64
64
  """
65
- if not model:
65
+ if not model or model == "Qwen2.5-72B":
66
66
  # model = "Qwen2.5-72B"
67
67
  model = "Qwen3.5-122B-A10B"
68
68
  kwargs["presence_penalty"] = 0
@@ -9,6 +9,46 @@ from sycommon.config.Config import Config
9
9
  from sycommon.logging.kafka_log import SYLogger
10
10
 
11
11
 
12
+ def get_webhook() -> Optional[str]:
13
+ """
14
+ 获取企业微信 WebHook 配置
15
+
16
+ 支持两种配置格式:
17
+ 1. 字符串格式(旧版):
18
+ llm:
19
+ WebHook: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx
20
+
21
+ 2. 对象格式(新版,支持启用开关):
22
+ llm:
23
+ WebHook:
24
+ enabled: true
25
+ url: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx
26
+ """
27
+ try:
28
+ config = Config().config
29
+ webhook_config = config.get('llm', {}).get('WebHook')
30
+
31
+ if webhook_config is None:
32
+ return None
33
+
34
+ # 字符串格式(旧版兼容)
35
+ if isinstance(webhook_config, str):
36
+ return webhook_config
37
+
38
+ # 对象格式(新版)
39
+ if isinstance(webhook_config, dict):
40
+ # 检查是否启用
41
+ if not webhook_config.get('enabled', True):
42
+ SYLogger.debug("企业微信 WebHook 已禁用")
43
+ return None
44
+ return webhook_config.get('url')
45
+
46
+ return None
47
+ except Exception as e:
48
+ SYLogger.warning(f"读取 WebHook 配置失败: {str(e)}")
49
+ return None
50
+
51
+
12
52
  async def send_wechat_markdown_msg(
13
53
  content: str,
14
54
  webhook: str = None
@@ -55,8 +95,7 @@ async def send_webhook(error_info: dict = None, webhook: str = None):
55
95
  config = Config().config
56
96
  service_name = config.get('Name', "未知服务")
57
97
  env = config.get('Nacos', {}).get('namespaceId', '未知环境')
58
- # 注意:这里使用了大写开头的 WebHook,请确保配置文件中键名一致
59
- webHook = config.get('llm', {}).get('WebHook')
98
+ webHook = get_webhook()
60
99
  except Exception as e:
61
100
  service_name = "未知服务"
62
101
  env = "未知环境"
@@ -186,3 +225,122 @@ def run(*args, webhook: str = None, **kwargs):
186
225
 
187
226
  # 只有确实有错误时才以状态码 1 退出
188
227
  sys.exit(1)
228
+
229
+
230
+ async def send_mq_disconnect_alert(
231
+ error_msg: str,
232
+ host: str = None,
233
+ app_name: str = None,
234
+ disconnect_count: int = 0,
235
+ reconnect_attempts: int = 0,
236
+ is_recovered: bool = False
237
+ ) -> Optional[dict]:
238
+ """
239
+ 发送 MQ 连接断开告警
240
+
241
+ :param error_msg: 错误信息
242
+ :param host: RabbitMQ 主机地址
243
+ :param app_name: 应用名称(MQ连接名)
244
+ :param disconnect_count: 累计断开次数
245
+ :param reconnect_attempts: 重连尝试次数
246
+ :param is_recovered: 是否已恢复
247
+ :return: 发送结果
248
+ """
249
+ try:
250
+ config = Config().config
251
+ service_name = config.get('Name', "未知服务")
252
+ env = config.get('Nacos', {}).get('namespaceId', '未知环境')
253
+ except Exception:
254
+ service_name = "未知服务"
255
+ env = "未知环境"
256
+
257
+ webhook = get_webhook()
258
+ if not webhook:
259
+ SYLogger.debug("未配置企业微信 WebHook,跳过 MQ 断连告警")
260
+ return None
261
+
262
+ alert_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
263
+ # 显示服务名和应用名
264
+ display_name = f"{service_name}" + (f" ({app_name})" if app_name else "")
265
+
266
+ if is_recovered:
267
+ # 恢复通知
268
+ markdown_content = f"""### {display_name} RabbitMQ 连接已恢复 ✅
269
+ > 环境: <font color="info">{env}</font>
270
+ > 时间: <font color="comment">{alert_time}</font>
271
+ > 节点: <font color="comment">{host or '未知'}</font>
272
+ > 恢复前重试次数: {reconnect_attempts}
273
+ > 本次断开次数: {disconnect_count}"""
274
+ else:
275
+ # 断开告警
276
+ markdown_content = f"""### {display_name} RabbitMQ 连接断开告警 🚨
277
+ > 环境: <font color="warning">{env}</font>
278
+ > 时间: <font color="comment">{alert_time}</font>
279
+ > 节点: <font color="comment">{host or '未知'}</font>
280
+ > 累计断开次数: <font color="danger">{disconnect_count}</font>
281
+ > 重连尝试: {reconnect_attempts} 次
282
+ > 错误信息: <font color="danger">{error_msg}</font>"""
283
+
284
+ return await send_wechat_markdown_msg(
285
+ content=markdown_content,
286
+ webhook=webhook
287
+ )
288
+
289
+
290
+ async def send_nacos_disconnect_alert(
291
+ error_msg: str,
292
+ service_name: str = None,
293
+ host: str = None,
294
+ disconnect_count: int = 0,
295
+ fail_count: int = 0,
296
+ is_recovered: bool = False
297
+ ) -> Optional[dict]:
298
+ """
299
+ 发送 Nacos 连接断开告警
300
+
301
+ :param error_msg: 错误信息
302
+ :param service_name: 服务名称
303
+ :param host: 服务地址
304
+ :param disconnect_count: 累计断开次数
305
+ :param fail_count: 连续失败次数
306
+ :param is_recovered: 是否已恢复
307
+ :return: 发送结果
308
+ """
309
+ try:
310
+ config = Config().config
311
+ display_service_name = config.get('Name', "未知服务")
312
+ env = config.get('Nacos', {}).get('namespaceId', '未知环境')
313
+ except Exception:
314
+ display_service_name = "未知服务"
315
+ env = "未知环境"
316
+
317
+ webhook = get_webhook()
318
+ if not webhook:
319
+ SYLogger.debug("未配置企业微信 WebHook,跳过 Nacos 断连告警")
320
+ return None
321
+
322
+ alert_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
323
+ # 显示服务名
324
+ display_name = service_name or display_service_name
325
+
326
+ if is_recovered:
327
+ # 恢复通知
328
+ markdown_content = f"""### {display_name} Nacos 心跳已恢复 ✅
329
+ > 环境: <font color="info">{env}</font>
330
+ > 时间: <font color="comment">{alert_time}</font>
331
+ > 服务地址: <font color="comment">{host or '未知'}</font>
332
+ > 累计断开次数: {disconnect_count}"""
333
+ else:
334
+ # 断开告警
335
+ markdown_content = f"""### {display_name} Nacos 心跳失败告警 🚨
336
+ > 环境: <font color="warning">{env}</font>
337
+ > 时间: <font color="comment">{alert_time}</font>
338
+ > 服务地址: <font color="comment">{host or '未知'}</font>
339
+ > 累计断开次数: <font color="danger">{disconnect_count}</font>
340
+ > 连续失败: {fail_count} 次
341
+ > 错误信息: <font color="danger">{error_msg}</font>"""
342
+
343
+ return await send_wechat_markdown_msg(
344
+ content=markdown_content,
345
+ webhook=webhook
346
+ )
@@ -4,6 +4,7 @@ from typing import Optional, List, Tuple
4
4
  from aio_pika import connect_robust
5
5
  from aio_pika.abc import AbstractChannel, AbstractRobustConnection
6
6
  from sycommon.logging.kafka_log import SYLogger
7
+ from sycommon.notice.uvicorn_monitor import send_mq_disconnect_alert
7
8
 
8
9
  logger = SYLogger
9
10
 
@@ -18,6 +19,15 @@ class RabbitMQConnectionPool:
18
19
  3. 增强连接探活与重建机制。
19
20
  """
20
21
 
22
+ # 心跳重试配置
23
+ HEARTBEAT_RETRY_COUNT = 3 # 心跳失败重试次数
24
+ HEARTBEAT_RETRY_INTERVAL = 10 # 心跳重试间隔(秒)
25
+
26
+ # 告警状态(类级别,用于跨实例统计)
27
+ _alert_sent: bool = False # 是否已发送断连告警
28
+ _reconnect_attempts: int = 0 # 当前重连尝试次数
29
+ _disconnect_count: int = 0 # 累计断开次数
30
+
21
31
  def __init__(
22
32
  self,
23
33
  hosts: List[str],
@@ -59,13 +69,84 @@ class RabbitMQConnectionPool:
59
69
  self._initialized = False
60
70
  self._is_shutdown = False
61
71
 
72
+ # 心跳重试计数器
73
+ self._heartbeat_fail_count = 0
74
+
62
75
  async def is_alive(self) -> bool:
63
- """对外暴露的连接存活状态"""
76
+ """对外暴露的连接存活状态(带心跳重试机制)
77
+
78
+ 心跳检测失败时不会立即判定为断开,而是重试3次后才断开。
79
+ """
64
80
  if self._is_shutdown:
65
81
  return False
66
82
  if not self._initialized:
67
83
  return False
68
- return self._connection is not None and not self._connection.is_closed
84
+
85
+ # 基础连接检查
86
+ if self._connection is None or self._connection.is_closed:
87
+ self._heartbeat_fail_count += 1
88
+ logger.warning(
89
+ f"⚠️ [HEARTBEAT] 连接已断开 (失败计数: {self._heartbeat_fail_count}/{self.HEARTBEAT_RETRY_COUNT})"
90
+ )
91
+ if self._heartbeat_fail_count >= self.HEARTBEAT_RETRY_COUNT:
92
+ logger.error("❌ [HEARTBEAT] 心跳重试次数已达上限,判定连接死亡")
93
+ # 发送断连告警(仅发送一次)
94
+ if not self._alert_sent:
95
+ self._alert_sent = True
96
+ self._disconnect_count += 1
97
+ asyncio.create_task(send_mq_disconnect_alert(
98
+ error_msg="心跳检测连续失败,连接已断开",
99
+ host=self._current_host,
100
+ app_name=self.app_name,
101
+ disconnect_count=self._disconnect_count,
102
+ reconnect_attempts=self._reconnect_attempts
103
+ ))
104
+ return False
105
+ # 未达上限,暂时认为存活(等待重试)
106
+ return True
107
+
108
+ # 内部通道探活检查
109
+ try:
110
+ if self._internal_channel is None or self._internal_channel.is_closed:
111
+ self._internal_channel = await self._connection.channel()
112
+ # 探活成功,重置失败计数器
113
+ self._heartbeat_fail_count = 0
114
+ # 如果之前发送过告警,现在恢复,发送恢复通知
115
+ if self._alert_sent:
116
+ self._alert_sent = False
117
+ saved_reconnect_attempts = self._reconnect_attempts
118
+ saved_disconnect_count = self._disconnect_count
119
+ self._reconnect_attempts = 0
120
+ asyncio.create_task(send_mq_disconnect_alert(
121
+ error_msg="连接已恢复",
122
+ host=self._current_host,
123
+ app_name=self.app_name,
124
+ disconnect_count=saved_disconnect_count,
125
+ reconnect_attempts=saved_reconnect_attempts,
126
+ is_recovered=True
127
+ ))
128
+ return True
129
+ except Exception as e:
130
+ self._heartbeat_fail_count += 1
131
+ logger.warning(
132
+ f"⚠️ [HEARTBEAT] 连接探活失败: {e} (失败计数: {self._heartbeat_fail_count}/{self.HEARTBEAT_RETRY_COUNT})"
133
+ )
134
+ if self._heartbeat_fail_count >= self.HEARTBEAT_RETRY_COUNT:
135
+ logger.error("❌ [HEARTBEAT] 心跳重试次数已达上限,判定连接死亡")
136
+ # 发送断连告警(仅发送一次)
137
+ if not self._alert_sent:
138
+ self._alert_sent = True
139
+ self._disconnect_count += 1
140
+ asyncio.create_task(send_mq_disconnect_alert(
141
+ error_msg=str(e),
142
+ host=self._current_host,
143
+ app_name=self.app_name,
144
+ disconnect_count=self._disconnect_count,
145
+ reconnect_attempts=self._reconnect_attempts
146
+ ))
147
+ return False
148
+ # 未达上限,暂时认为存活(等待重试)
149
+ return True
69
150
 
70
151
  async def _cleanup_resources(self):
71
152
  """彻底清理资源"""
@@ -135,6 +216,7 @@ class RabbitMQConnectionPool:
135
216
 
136
217
  for host in retry_hosts:
137
218
  self._current_host = host
219
+ self._reconnect_attempts += 1
138
220
  try:
139
221
  self._connection = await self._create_connection_impl(host)
140
222
  self._initialized = True
@@ -148,6 +230,24 @@ class RabbitMQConnectionPool:
148
230
  self._initialized = False
149
231
  raise ConnectionError("所有 RabbitMQ 节点连接失败") from last_error
150
232
 
233
+ # 重连成功,发送恢复通知
234
+ if self._alert_sent:
235
+ self._alert_sent = False
236
+ saved_reconnect_attempts = self._reconnect_attempts
237
+ saved_disconnect_count = self._disconnect_count
238
+ self._reconnect_attempts = 0
239
+ asyncio.create_task(send_mq_disconnect_alert(
240
+ error_msg="连接重连成功",
241
+ host=self._current_host,
242
+ app_name=self.app_name,
243
+ disconnect_count=saved_disconnect_count,
244
+ reconnect_attempts=saved_reconnect_attempts,
245
+ is_recovered=True
246
+ ))
247
+
248
+ # 连接正常,重置心跳失败计数器
249
+ self._heartbeat_fail_count = 0
250
+
151
251
  return self._connection
152
252
 
153
253
  async def init_pools(self):
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  import threading
2
3
  import time
3
4
  from sycommon.logging.kafka_log import SYLogger
@@ -5,9 +6,42 @@ from sycommon.synacos.nacos_client_base import NacosClientBase
5
6
  from sycommon.synacos.nacos_service_registration import NacosServiceRegistration
6
7
 
7
8
 
9
+ def send_nacos_alert_sync(
10
+ error_msg: str,
11
+ service_name: str = None,
12
+ host: str = None,
13
+ disconnect_count: int = 0,
14
+ fail_count: int = 0,
15
+ is_recovered: bool = False
16
+ ):
17
+ """同步方式发送 Nacos 告警(用于在线程中调用)"""
18
+ try:
19
+ # 创建新的事件循环
20
+ loop = asyncio.new_event_loop()
21
+ asyncio.set_event_loop(loop)
22
+ try:
23
+ from sycommon.notice.uvicorn_monitor import send_nacos_disconnect_alert
24
+ loop.run_until_complete(send_nacos_disconnect_alert(
25
+ error_msg=error_msg,
26
+ service_name=service_name,
27
+ host=host,
28
+ disconnect_count=disconnect_count,
29
+ fail_count=fail_count,
30
+ is_recovered=is_recovered
31
+ ))
32
+ finally:
33
+ loop.close()
34
+ except Exception as e:
35
+ SYLogger.warning(f"发送 Nacos 告警失败: {e}")
36
+
37
+
8
38
  class NacosHeartbeatManager:
9
39
  """Nacos心跳管理类 - 负责心跳发送和监控"""
10
40
 
41
+ # 告警状态(类级别)
42
+ _alert_sent: bool = False # 是否已发送断连告警
43
+ _disconnect_count: int = 0 # 累计断开次数
44
+
11
45
  def __init__(self, client_base: NacosClientBase, registration: NacosServiceRegistration, heartbeat_interval: int = 15):
12
46
  self.client_base = client_base
13
47
  self.registration = registration
@@ -75,8 +109,20 @@ class NacosHeartbeatManager:
75
109
  SYLogger.info(
76
110
  f"nacos:心跳发送成功 - 间隔: {self.heartbeat_interval}秒"
77
111
  )
112
+ # 恢复后发送通知
113
+ if self._alert_sent:
114
+ self._alert_sent = False
115
+ send_nacos_alert_sync(
116
+ error_msg="心跳恢复正常",
117
+ service_name=self.registration.service_name,
118
+ host=f"{self.registration.real_ip}:{self.registration.port}",
119
+ disconnect_count=self._disconnect_count,
120
+ fail_count=0,
121
+ is_recovered=True
122
+ )
78
123
  else:
79
124
  consecutive_fail += 1
125
+ self._heartbeat_fail_count += 1
80
126
  SYLogger.warning(
81
127
  f"nacos:心跳发送失败 - 连续失败: {consecutive_fail}次"
82
128
  )
@@ -85,11 +131,38 @@ class NacosHeartbeatManager:
85
131
  self.client_base.reconnect_nacos_client()
86
132
  consecutive_fail = 0
87
133
 
134
+ # 连续失败3次后发送告警(仅发送一次)
135
+ if consecutive_fail >= 3 and not self._alert_sent:
136
+ self._alert_sent = True
137
+ self._disconnect_count += 1
138
+ send_nacos_alert_sync(
139
+ error_msg=f"心跳连续失败{consecutive_fail}次",
140
+ service_name=self.registration.service_name,
141
+ host=f"{self.registration.real_ip}:{self.registration.port}",
142
+ disconnect_count=self._disconnect_count,
143
+ fail_count=consecutive_fail,
144
+ is_recovered=False
145
+ )
146
+
88
147
  except Exception as e:
89
148
  consecutive_fail += 1
149
+ self._heartbeat_fail_count += 1
90
150
  SYLogger.error(
91
151
  f"nacos:心跳异常: {str(e)}, 连续失败: {consecutive_fail}次")
92
152
 
153
+ # 异常情况下也发送告警
154
+ if consecutive_fail >= 3 and not self._alert_sent:
155
+ self._alert_sent = True
156
+ self._disconnect_count += 1
157
+ send_nacos_alert_sync(
158
+ error_msg=f"心跳异常: {str(e)}",
159
+ service_name=self.registration.service_name,
160
+ host=f"{self.registration.real_ip}:{self.registration.port}",
161
+ disconnect_count=self._disconnect_count,
162
+ fail_count=consecutive_fail,
163
+ is_recovered=False
164
+ )
165
+
93
166
  # 计算剩余等待时间,确保心跳间隔精确
94
167
  elapsed = time.time() - heartbeat_start_time
95
168
  remaining_wait = max(0, self.heartbeat_interval - elapsed)
@@ -1,13 +1,44 @@
1
+ import asyncio
1
2
  import threading
3
+ import time
2
4
  from typing import List, Dict
3
5
  from sycommon.logging.kafka_log import SYLogger
4
6
  from sycommon.synacos.nacos_client_base import NacosClientBase
5
7
  from sycommon.synacos.nacos_service_registration import NacosServiceRegistration
6
8
 
7
9
 
10
+ def send_nacos_service_alert_sync(
11
+ error_msg: str,
12
+ service_name: str = None,
13
+ host: str = None,
14
+ is_service_down: bool = False
15
+ ):
16
+ """同步方式发送 Nacos 服务告警(用于在线程中调用)"""
17
+ try:
18
+ loop = asyncio.new_event_loop()
19
+ asyncio.set_event_loop(loop)
20
+ try:
21
+ from sycommon.notice.uvicorn_monitor import send_nacos_disconnect_alert
22
+ loop.run_until_complete(send_nacos_disconnect_alert(
23
+ error_msg=error_msg,
24
+ service_name=service_name,
25
+ host=host,
26
+ disconnect_count=1 if is_service_down else 0,
27
+ fail_count=1,
28
+ is_recovered=False
29
+ ))
30
+ finally:
31
+ loop.close()
32
+ except Exception as e:
33
+ SYLogger.warning(f"发送 Nacos 服务告警失败: {e}")
34
+
35
+
8
36
  class NacosServiceDiscovery:
9
37
  """Nacos服务发现类 - 负责服务实例发现和轮询"""
10
38
 
39
+ # 告警状态
40
+ _service_alert_sent: bool = False
41
+
11
42
  def __init__(self, client_base: NacosClientBase):
12
43
  self.client_base = client_base
13
44
 
@@ -137,6 +168,15 @@ class NacosServiceDiscovery:
137
168
  registration.registered = current_registered
138
169
  if not current_registered:
139
170
  SYLogger.warning("nacos:服务实例未注册,触发单次重新注册")
171
+ # 发送服务不可用告警
172
+ if not self._service_alert_sent:
173
+ self._service_alert_sent = True
174
+ send_nacos_service_alert_sync(
175
+ error_msg="服务实例在Nacos中已失效",
176
+ service_name=registration.service_name,
177
+ host=f"{registration.real_ip}:{registration.port}",
178
+ is_service_down=True
179
+ )
140
180
  retry_thread = threading.Thread(
141
181
  target=registration.register,
142
182
  args=(True,),
@@ -146,7 +186,21 @@ class NacosServiceDiscovery:
146
186
  retry_thread.start()
147
187
  else:
148
188
  SYLogger.info("nacos:服务实例已注册,触发单次验证")
189
+ # 恢复后重置告警状态
190
+ if self._service_alert_sent:
191
+ self._service_alert_sent = False
192
+ # 发送恢复通知
193
+ send_nacos_service_alert_sync(
194
+ error_msg="服务实例已恢复注册",
195
+ service_name=registration.service_name,
196
+ host=f"{registration.real_ip}:{registration.port}",
197
+ is_service_down=False
198
+ )
149
199
  registration.verify_registration()
200
+ else:
201
+ # 服务正常,重置告警状态
202
+ if self._service_alert_sent and current_registered:
203
+ self._service_alert_sent = False
150
204
 
151
205
  self.client_base._shutdown_event.wait(check_interval)
152
206
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sycommon-python-lib
3
- Version: 0.2.0b16
3
+ Version: 0.2.0b18
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown