- 新增重试和失败告警功能(支持自动重试N次,失败后钉钉/企微通知) - 新增密钥管理(安全存储API Key等敏感信息) - 新增脚本模板库(预置常用脚本模板) - 新增脚本版本管理(自动保存历史版本,支持回滚) - 新增执行统计(成功率、平均耗时、7日趋势) - SDK 新增多租户遍历能力(get_tenants/get_tenant_config/get_all_tenant_configs) - SDK 新增密钥读取方法(get_secret)
This commit is contained in:
@@ -24,6 +24,8 @@ class ScriptSDK:
|
||||
- HTTP 请求
|
||||
- 变量存储(跨执行持久化)
|
||||
- 日志记录
|
||||
- 多租户遍历
|
||||
- 密钥管理
|
||||
"""
|
||||
|
||||
def __init__(self, tenant_id: str, task_id: int, trace_id: str = None):
|
||||
@@ -32,6 +34,7 @@ class ScriptSDK:
|
||||
self.trace_id = trace_id or f"script_{task_id}_{datetime.now().strftime('%Y%m%d%H%M%S')}"
|
||||
self._logs: List[str] = []
|
||||
self._db: Optional[Session] = None
|
||||
self._tenants_cache: Optional[List[Dict]] = None # 租户列表缓存
|
||||
|
||||
def _get_db(self) -> Session:
|
||||
"""获取数据库会话"""
|
||||
@@ -393,6 +396,171 @@ class ScriptSDK:
|
||||
self.log(f"删除变量失败: {str(e)}", level="ERROR")
|
||||
return False
|
||||
|
||||
# ============ 多租户遍历 ============
|
||||
|
||||
def get_tenants(self, app_code: str = None) -> List[Dict]:
|
||||
"""
|
||||
获取租户列表(用于多租户任务遍历)
|
||||
|
||||
Args:
|
||||
app_code: 应用代码(可选),筛选订阅了该应用的租户
|
||||
|
||||
Returns:
|
||||
租户列表 [{"code": "xxx", "name": "租户名", "custom_configs": {...}}]
|
||||
"""
|
||||
db = self._get_db()
|
||||
try:
|
||||
if app_code:
|
||||
# 筛选订阅了指定应用的租户
|
||||
result = db.execute(
|
||||
text("""
|
||||
SELECT DISTINCT t.code, t.name, ta.custom_configs
|
||||
FROM platform_tenants t
|
||||
INNER JOIN platform_tenant_apps ta ON t.code = ta.tenant_id
|
||||
WHERE ta.app_code = :app_code AND t.status = 1
|
||||
"""),
|
||||
{"app_code": app_code}
|
||||
)
|
||||
else:
|
||||
# 获取所有启用的租户
|
||||
result = db.execute(
|
||||
text("SELECT code, name FROM platform_tenants WHERE status = 1")
|
||||
)
|
||||
|
||||
tenants = []
|
||||
for row in result.mappings().all():
|
||||
tenant = dict(row)
|
||||
# 解析 custom_configs
|
||||
if "custom_configs" in tenant and tenant["custom_configs"]:
|
||||
try:
|
||||
tenant["custom_configs"] = json.loads(tenant["custom_configs"])
|
||||
except:
|
||||
pass
|
||||
tenants.append(tenant)
|
||||
|
||||
self.log(f"获取租户列表成功,共 {len(tenants)} 个租户")
|
||||
return tenants
|
||||
except Exception as e:
|
||||
self.log(f"获取租户列表失败: {str(e)}", level="ERROR")
|
||||
return []
|
||||
|
||||
def get_tenant_config(self, tenant_id: str, app_code: str, key: str = None) -> Any:
|
||||
"""
|
||||
获取指定租户的应用配置
|
||||
|
||||
Args:
|
||||
tenant_id: 租户ID
|
||||
app_code: 应用代码
|
||||
key: 配置项键名(可选,不传返回全部配置)
|
||||
|
||||
Returns:
|
||||
配置值或配置字典
|
||||
"""
|
||||
db = self._get_db()
|
||||
try:
|
||||
result = db.execute(
|
||||
text("""
|
||||
SELECT custom_configs FROM platform_tenant_apps
|
||||
WHERE tenant_id = :tenant_id AND app_code = :app_code
|
||||
"""),
|
||||
{"tenant_id": tenant_id, "app_code": app_code}
|
||||
)
|
||||
row = result.first()
|
||||
|
||||
if not row or not row[0]:
|
||||
return None if key else {}
|
||||
|
||||
try:
|
||||
configs = json.loads(row[0])
|
||||
except:
|
||||
configs = {}
|
||||
|
||||
if key:
|
||||
return configs.get(key)
|
||||
return configs
|
||||
except Exception as e:
|
||||
self.log(f"获取租户配置失败: {str(e)}", level="ERROR")
|
||||
return None if key else {}
|
||||
|
||||
def get_all_tenant_configs(self, app_code: str) -> List[Dict]:
|
||||
"""
|
||||
获取所有租户的应用配置(便捷方法,用于批量操作)
|
||||
|
||||
Args:
|
||||
app_code: 应用代码
|
||||
|
||||
Returns:
|
||||
[{"tenant_id": "xxx", "tenant_name": "租户名", "configs": {...}}]
|
||||
"""
|
||||
db = self._get_db()
|
||||
try:
|
||||
result = db.execute(
|
||||
text("""
|
||||
SELECT t.code as tenant_id, t.name as tenant_name, ta.custom_configs
|
||||
FROM platform_tenants t
|
||||
INNER JOIN platform_tenant_apps ta ON t.code = ta.tenant_id
|
||||
WHERE ta.app_code = :app_code AND t.status = 1
|
||||
"""),
|
||||
{"app_code": app_code}
|
||||
)
|
||||
|
||||
tenants = []
|
||||
for row in result.mappings().all():
|
||||
configs = {}
|
||||
if row["custom_configs"]:
|
||||
try:
|
||||
configs = json.loads(row["custom_configs"])
|
||||
except:
|
||||
pass
|
||||
tenants.append({
|
||||
"tenant_id": row["tenant_id"],
|
||||
"tenant_name": row["tenant_name"],
|
||||
"configs": configs
|
||||
})
|
||||
|
||||
self.log(f"获取 {app_code} 应用的租户配置,共 {len(tenants)} 个")
|
||||
return tenants
|
||||
except Exception as e:
|
||||
self.log(f"获取租户配置失败: {str(e)}", level="ERROR")
|
||||
return []
|
||||
|
||||
# ============ 密钥管理 ============
|
||||
|
||||
def get_secret(self, key: str) -> Optional[str]:
|
||||
"""
|
||||
获取密钥(优先读取租户级密钥,其次读取全局密钥)
|
||||
|
||||
Args:
|
||||
key: 密钥名称
|
||||
|
||||
Returns:
|
||||
密钥值(如不存在返回 None)
|
||||
"""
|
||||
db = self._get_db()
|
||||
try:
|
||||
# 优先查询租户级密钥
|
||||
result = db.execute(
|
||||
text("""
|
||||
SELECT secret_value FROM platform_secrets
|
||||
WHERE (tenant_id = :tenant_id OR tenant_id IS NULL)
|
||||
AND secret_key = :key
|
||||
ORDER BY tenant_id DESC
|
||||
LIMIT 1
|
||||
"""),
|
||||
{"tenant_id": self.tenant_id, "key": key}
|
||||
)
|
||||
row = result.first()
|
||||
|
||||
if row:
|
||||
self.log(f"获取密钥成功: {key}")
|
||||
return row[0]
|
||||
|
||||
self.log(f"密钥不存在: {key}", level="WARN")
|
||||
return None
|
||||
except Exception as e:
|
||||
self.log(f"获取密钥失败: {str(e)}", level="ERROR")
|
||||
return None
|
||||
|
||||
# ============ 日志 ============
|
||||
|
||||
def log(self, message: str, level: str = "INFO"):
|
||||
|
||||
Reference in New Issue
Block a user