| 
					
				 | 
			
			
				@@ -25,6 +25,8 @@ from common import ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from config import TASK_RETRY_CONFIG, SCRIPTS_BASE_PATH, PG_CONFIG, NEO4J_CONFIG 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import pytz 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import pandas as pd 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import sys 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # 创建日志记录器 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 logger = logging.getLogger(__name__) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -63,6 +65,21 @@ class DecimalEncoder(json.JSONEncoder): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return obj.isoformat() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # 让父类处理其他类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return super(DecimalEncoder, self).default(obj) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def get_logical_exec_date(logical_date): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    获取逻辑执行日期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    参数: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logical_date: 逻辑执行日期,UTC时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    返回: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logical_exec_date: 逻辑执行日期,北京时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 获取逻辑执行日期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return logical_date.in_timezone('Asia/Shanghai').to_date_string() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ############################################# 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # 脚本执行函数 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -91,6 +108,237 @@ def execute_script(script_id, script_name, target_table, exec_date, script_exec_ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     logger.info(f"script_exec_mode: {script_exec_mode}, 类型: {type(script_exec_mode)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     logger.info(f"exec_date: {exec_date}, 类型: {type(exec_date)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 记录额外参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for key, value in kwargs.items(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.info(f"额外参数 - {key}: {value}, 类型: {type(value)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 获取逻辑执行日期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logical_exec_date = get_logical_exec_date(exec_date) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"逻辑执行日期: {logical_exec_date}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 检查script_name是否为空 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if not script_name: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.error(f"脚本ID {script_id} 的script_name为空,无法执行") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 记录执行开始时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    start_time = datetime.now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 导入和执行脚本模块 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        import importlib.util 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        import sys 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        script_path = os.path.join(SCRIPTS_BASE_PATH, script_name) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 获取脚本类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        script_type = kwargs.get('script_type', 'python_script') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 只有当脚本类型为 sql_script 或 python_script 时才检查文件是否存在 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if script_type in ['sql_script', 'python_script']: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if not os.path.exists(script_path): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                logger.error(f"脚本文件不存在: {script_path}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 动态导入模块 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            spec = importlib.util.spec_from_file_location("dynamic_module", script_path) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            module = importlib.util.module_from_spec(spec) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            spec.loader.exec_module(module) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 对于其他类型,例如默认python类型,我们将使用其他执行方式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"脚本类型为 {script_type},不检查脚本文件是否存在") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 这里我们将直接退出,因为对于python类型应使用execute_python_script函数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.error(f"脚本类型为 {script_type},应使用专用函数执行,而不是execute_script") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 检查并调用标准入口函数run 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if hasattr(module, "run"): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"调用脚本 {script_name} 的标准入口函数 run()") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 构建完整的参数字典 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            run_params = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "table_name": target_table, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "execution_mode": script_exec_mode, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "exec_date": exec_date 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ## 添加可能的额外参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for key in ['target_type', 'storage_location', 'frequency', 'source_tables']: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if key in kwargs and kwargs[key] is not None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    run_params[key] = kwargs[key]  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 调用脚本的run函数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"调用run函数并传递参数: {run_params}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            result = module.run(**run_params) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"脚本执行完成,原始返回值: {result}, 类型: {type(result)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 确保result是布尔值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if result is None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                logger.warning(f"脚本返回值为None,转换为False") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                result = False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            elif not isinstance(result, bool): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                original_result = result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                result = bool(result) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                logger.warning(f"脚本返回非布尔值 {original_result},转换为布尔值: {result}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 记录结束时间和结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            end_time = datetime.now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            duration = (end_time - start_time).total_seconds() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"脚本 {script_name} 执行完成,结果: {result}, 耗时: {duration:.2f}秒") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.error(f"脚本 {script_name} 中未定义标准入口函数 run(),无法执行") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    except Exception as e: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 处理异常 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.error(f"执行脚本 {script_id} 出错: {str(e)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        end_time = datetime.now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        duration = (end_time - start_time).total_seconds() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.error(f"脚本 {script_name} 执行失败,耗时: {duration:.2f}秒") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.info(f"===== 脚本执行异常结束 =====") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        import traceback 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.error(traceback.format_exc()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 确保不会阻塞DAG 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def execute_sql_script(script_id, script_name, target_table, exec_date, script_exec_mode='append', **kwargs): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    执行SQL脚本并返回执行结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    参数: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        script_id: 脚本ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        script_name: 脚本名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        target_table: 目标表名 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        exec_date: 执行日期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        script_exec_mode: 执行模式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        **kwargs: 其他参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    返回: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        bool: 脚本执行结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 添加详细日志 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"===== 开始执行SQL脚本 {script_id} =====") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"script_id: {script_id}, 类型: {type(script_id)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"script_name: {script_name}, 类型: {type(script_name)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"target_table: {target_table}, 类型: {type(target_table)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"script_exec_mode: {script_exec_mode}, 类型: {type(script_exec_mode)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"exec_date: {exec_date}, 类型: {type(exec_date)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 记录额外参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for key, value in kwargs.items(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.info(f"额外参数 - {key}: {value}, 类型: {type(value)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 记录执行开始时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    start_time = datetime.now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 导入和执行execution_sql模块 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        import importlib.util 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        import sys 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        exec_sql_path = os.path.join(SCRIPTS_BASE_PATH, "execution_sql.py") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 对于SQL类型的脚本,我们不检查它是否作为文件存在 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 但是我们需要检查execution_sql.py是否存在 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if not os.path.exists(exec_sql_path): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.error(f"SQL执行脚本文件不存在: {exec_sql_path}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 动态导入execution_sql模块 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            spec = importlib.util.spec_from_file_location("execution_sql", exec_sql_path) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            exec_sql_module = importlib.util.module_from_spec(spec) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            spec.loader.exec_module(exec_sql_module) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"成功导入 execution_sql 模块") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        except Exception as import_err: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.error(f"导入 execution_sql 模块时出错: {str(import_err)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            import traceback 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.error(traceback.format_exc()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 检查并调用标准入口函数run 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if hasattr(exec_sql_module, "run"): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"调用执行SQL脚本的标准入口函数 run()") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 获取频率参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            frequency = kwargs.get('frequency', 'daily')  # 默认为daily 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 构建完整的参数字典 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            run_params = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "script_type": "sql", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "target_table": target_table, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "script_name": script_name, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "exec_date": exec_date, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "frequency": frequency, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "target_table_label": kwargs.get('target_table_label', ''), # 传递目标表标签,用于ETL幂等性判断 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "execution_mode": script_exec_mode  # 传递执行模式参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 添加可能的额外参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for key in ['target_type', 'storage_location', 'source_tables']: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if key in kwargs and kwargs[key] is not None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    run_params[key] = kwargs[key] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 调用execution_sql.py的run函数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"调用SQL执行脚本的run函数并传递参数: {run_params}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            result = exec_sql_module.run(**run_params) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"SQL脚本执行完成,原始返回值: {result}, 类型: {type(result)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 确保result是布尔值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if result is None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                logger.warning(f"SQL脚本返回值为None,转换为False") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                result = False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            elif not isinstance(result, bool): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                original_result = result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                result = bool(result) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                logger.warning(f"SQL脚本返回非布尔值 {original_result},转换为布尔值: {result}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 记录结束时间和结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            end_time = datetime.now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            duration = (end_time - start_time).total_seconds() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"SQL脚本 {script_name} 执行完成,结果: {result}, 耗时: {duration:.2f}秒") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.error(f"执行SQL脚本 execution_sql.py 中未定义标准入口函数 run(),无法执行") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    except Exception as e: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 处理异常 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.error(f"执行SQL脚本 {script_id} 出错: {str(e)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        end_time = datetime.now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        duration = (end_time - start_time).total_seconds() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.error(f"SQL脚本 {script_name} 执行失败,耗时: {duration:.2f}秒") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.info(f"===== SQL脚本执行异常结束 =====") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        import traceback 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.error(traceback.format_exc()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 确保不会阻塞DAG 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# 重命名此函数为execute_python_script 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def execute_python_script(script_id, script_name, target_table, exec_date, script_exec_mode='append', **kwargs): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    执行Python脚本文件并返回执行结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    参数: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        script_id: 脚本ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        script_name: 脚本文件名(.py文件) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        target_table: 目标表名 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        exec_date: 执行日期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        script_exec_mode: 执行模式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        **kwargs: 其他参数,如source_tables、target_type等 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    返回: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        bool: 脚本执行结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 添加详细日志 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"===== 开始执行Python脚本文件 {script_id} =====") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"script_id: {script_id}, 类型: {type(script_id)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"script_name: {script_name}, 类型: {type(script_name)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"target_table: {target_table}, 类型: {type(target_table)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"script_exec_mode: {script_exec_mode}, 类型: {type(script_exec_mode)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"exec_date: {exec_date}, 类型: {type(exec_date)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     # 记录额外参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     for key, value in kwargs.items(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         logger.info(f"额外参数 - {key}: {value}, 类型: {type(value)}") 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -120,7 +368,7 @@ def execute_script(script_id, script_name, target_table, exec_date, script_exec_ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				          
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # 检查并调用标准入口函数run 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if hasattr(module, "run"): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            logger.info(f"调用脚本 {script_name} 的标准入口函数 run()") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"调用脚本文件 {script_name} 的标准入口函数 run()") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             # 构建完整的参数字典 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             run_params = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 "table_name": target_table, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -157,7 +405,7 @@ def execute_script(script_id, script_name, target_table, exec_date, script_exec_ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             logger.error(f"脚本 {script_name} 中未定义标准入口函数 run(),无法执行") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     except Exception as e: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        # a处理异常 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 处理异常 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         logger.error(f"执行脚本 {script_id} 出错: {str(e)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         end_time = datetime.now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         duration = (end_time - start_time).total_seconds() 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -169,6 +417,236 @@ def execute_script(script_id, script_name, target_table, exec_date, script_exec_ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # 确保不会阻塞DAG 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# 使用execute_sql函数代替之前的execute_sql_script 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def execute_sql(script_id, script_name, target_table, exec_date, script_exec_mode='append', **kwargs): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    执行SQL脚本并返回执行结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    参数: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        script_id: 脚本ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        script_name: 脚本名称(数据库中的名称) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        target_table: 目标表名 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        exec_date: 执行日期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        script_exec_mode: 执行模式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        **kwargs: 其他参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    返回: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        bool: 脚本执行结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 添加详细日志 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"===== 开始执行SQL脚本 {script_id} =====") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"script_id: {script_id}, 类型: {type(script_id)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"script_name: {script_name}, 类型: {type(script_name)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"target_table: {target_table}, 类型: {type(target_table)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"script_exec_mode: {script_exec_mode}, 类型: {type(script_exec_mode)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"exec_date: {exec_date}, 类型: {type(exec_date)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 记录额外参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for key, value in kwargs.items(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.info(f"额外参数 - {key}: {value}, 类型: {type(value)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 记录执行开始时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    start_time = datetime.now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 导入和执行execution_sql模块 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        import importlib.util 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        import sys 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        exec_sql_path = os.path.join(SCRIPTS_BASE_PATH, "execution_sql.py") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 对于SQL类型的脚本,我们不检查它是否作为文件存在 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 但是我们需要检查execution_sql.py是否存在 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if not os.path.exists(exec_sql_path): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.error(f"SQL执行脚本文件不存在: {exec_sql_path}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 动态导入execution_sql模块 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            spec = importlib.util.spec_from_file_location("execution_sql", exec_sql_path) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            exec_sql_module = importlib.util.module_from_spec(spec) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            spec.loader.exec_module(exec_sql_module) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"成功导入 execution_sql 模块") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        except Exception as import_err: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.error(f"导入 execution_sql 模块时出错: {str(import_err)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            import traceback 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.error(traceback.format_exc()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 检查并调用标准入口函数run 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if hasattr(exec_sql_module, "run"): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"调用执行SQL脚本的标准入口函数 run()") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 获取频率参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            frequency = kwargs.get('frequency', 'daily')  # 默认为daily 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 构建完整的参数字典 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            run_params = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "script_type": "sql", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "target_table": target_table, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "script_name": script_name, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "exec_date": exec_date, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "frequency": frequency, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "target_table_label": kwargs.get('target_table_label', ''), # 传递目标表标签,用于ETL幂等性判断 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "execution_mode": script_exec_mode  # 传递执行模式参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 添加可能的额外参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for key in ['target_type', 'storage_location', 'source_tables']: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if key in kwargs and kwargs[key] is not None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    run_params[key] = kwargs[key] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 调用execution_sql.py的run函数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"调用SQL执行脚本的run函数并传递参数: {run_params}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            result = exec_sql_module.run(**run_params) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"SQL脚本执行完成,原始返回值: {result}, 类型: {type(result)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 确保result是布尔值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if result is None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                logger.warning(f"SQL脚本返回值为None,转换为False") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                result = False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            elif not isinstance(result, bool): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                original_result = result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                result = bool(result) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                logger.warning(f"SQL脚本返回非布尔值 {original_result},转换为布尔值: {result}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 记录结束时间和结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            end_time = datetime.now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            duration = (end_time - start_time).total_seconds() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"SQL脚本 {script_name} 执行完成,结果: {result}, 耗时: {duration:.2f}秒") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.error(f"执行SQL脚本 execution_sql.py 中未定义标准入口函数 run(),无法执行") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    except Exception as e: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 处理异常 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.error(f"执行SQL脚本 {script_id} 出错: {str(e)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        end_time = datetime.now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        duration = (end_time - start_time).total_seconds() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.error(f"SQL脚本 {script_name} 执行失败,耗时: {duration:.2f}秒") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.info(f"===== SQL脚本执行异常结束 =====") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        import traceback 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.error(traceback.format_exc()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 确保不会阻塞DAG 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+# 使用execute_python函数代替之前的execute_python_script 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def execute_python(script_id, script_name, target_table, exec_date, script_exec_mode='append', **kwargs): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    执行Python脚本并返回执行结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    参数: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        script_id: 脚本ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        script_name: 脚本名称(数据库中的名称) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        target_table: 目标表名 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        exec_date: 执行日期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        script_exec_mode: 执行模式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        **kwargs: 其他参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    返回: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        bool: 脚本执行结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 添加详细日志 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"===== 开始执行Python脚本 {script_id} =====") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"script_id: {script_id}, 类型: {type(script_id)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"script_name: {script_name}, 类型: {type(script_name)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"target_table: {target_table}, 类型: {type(target_table)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"script_exec_mode: {script_exec_mode}, 类型: {type(script_exec_mode)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"exec_date: {exec_date}, 类型: {type(exec_date)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 记录额外参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for key, value in kwargs.items(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.info(f"额外参数 - {key}: {value}, 类型: {type(value)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # 记录执行开始时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    start_time = datetime.now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 导入和执行execution_python模块 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        import importlib.util 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        import sys 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        exec_python_path = os.path.join(SCRIPTS_BASE_PATH, "execution_python.py") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 对于Python类型的脚本,我们不检查它是否作为文件存在 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 但是我们需要检查execution_python.py是否存在 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if not os.path.exists(exec_python_path): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.error(f"Python执行脚本文件不存在: {exec_python_path}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 动态导入execution_python模块 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            spec = importlib.util.spec_from_file_location("execution_python", exec_python_path) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            exec_python_module = importlib.util.module_from_spec(spec) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            spec.loader.exec_module(exec_python_module) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"成功导入 execution_python 模块") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        except Exception as import_err: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.error(f"导入 execution_python 模块时出错: {str(import_err)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            import traceback 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.error(traceback.format_exc()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 检查并调用标准入口函数run 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if hasattr(exec_python_module, "run"): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"调用执行Python脚本的标准入口函数 run()") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 获取频率参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            frequency = kwargs.get('frequency', 'daily')  # 默认为daily 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 构建完整的参数字典 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            run_params = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "script_type": "python", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "target_table": target_table, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "script_name": script_name, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "exec_date": exec_date, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "frequency": frequency, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "target_table_label": kwargs.get('target_table_label', ''), # 传递目标表标签 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "execution_mode": script_exec_mode  # 传递执行模式参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 添加可能的额外参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for key in ['target_type', 'storage_location', 'source_tables']: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if key in kwargs and kwargs[key] is not None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    run_params[key] = kwargs[key] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 调用execution_python.py的run函数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"调用Python执行脚本的run函数并传递参数: {run_params}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            result = exec_python_module.run(**run_params) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"Python脚本执行完成,原始返回值: {result}, 类型: {type(result)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 确保result是布尔值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if result is None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                logger.warning(f"Python脚本返回值为None,转换为False") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                result = False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            elif not isinstance(result, bool): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                original_result = result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                result = bool(result) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                logger.warning(f"Python脚本返回非布尔值 {original_result},转换为布尔值: {result}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # 记录结束时间和结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            end_time = datetime.now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            duration = (end_time - start_time).total_seconds() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.info(f"Python脚本 {script_name} 执行完成,结果: {result}, 耗时: {duration:.2f}秒") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            logger.error(f"执行Python脚本 execution_python.py 中未定义标准入口函数 run(),无法执行") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    except Exception as e: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 处理异常 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.error(f"执行Python脚本 {script_id} 出错: {str(e)}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        end_time = datetime.now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        duration = (end_time - start_time).total_seconds() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.error(f"Python脚本 {script_name} 执行失败,耗时: {duration:.2f}秒") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.info(f"===== Python脚本执行异常结束 =====") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        import traceback 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        logger.error(traceback.format_exc()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # 确保不会阻塞DAG 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ############################################# 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 # 执行计划获取和处理函数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ############################################# 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -446,7 +924,7 @@ with DAG( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     now = datetime.now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     now_with_tz = now.replace(tzinfo=pytz.timezone('Asia/Shanghai')) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     default_exec_date = get_today_date() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    logger.info(f"【DAG初始化】当前时间: {now} / {now_with_tz}, 默认执行日期: {default_exec_date}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    logger.info(f"【DAG初始化】当前时间: {now} / {now_with_tz}, 默认执行日期(用于初始化,非实际执行日期): {default_exec_date}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ############################################# 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     # 准备阶段: 检查并创建执行计划 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -528,6 +1006,7 @@ with DAG( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 script_type = script.get("script_type", "python") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 script_exec_mode = script.get("script_exec_mode", "append") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 source_tables = script.get("source_tables", []) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                target_table_label = script.get("target_table_label", "") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 # 使用描述性的任务ID,包含脚本名称和目标表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 # 提取文件名 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -558,10 +1037,31 @@ with DAG( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     if key in script and script[key] is not None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         op_kwargs[key] = script[key] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                # 根据脚本类型和目标表标签选择执行函数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if script_type.lower() == 'sql' and target_table_label == 'DataModel': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    # 使用SQL脚本执行函数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    logger.info(f"脚本 {script_id} 是SQL类型且目标表标签为DataModel,使用execute_sql函数执行") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    python_callable = execute_sql 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                elif script_type.lower() == 'python' and target_table_label == 'DataModel': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    # 使用Python脚本执行函数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    logger.info(f"脚本 {script_id} 是Python类型且目标表标签为DataModel,使用execute_python函数执行") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    python_callable = execute_python 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                elif script_type.lower() == 'python_script': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    # 使用Python脚本文件执行函数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    logger.info(f"脚本 {script_id} 是python_script类型,使用execute_python_script函数执行") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    python_callable = execute_python_script 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    # 默认使用Python脚本文件执行函数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    logger.warning(f"未识别的脚本类型 {script_type},使用默认execute_python_script函数执行") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    python_callable = execute_python_script 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                # 确保target_table_label被传递 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                op_kwargs["target_table_label"] = target_table_label 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 # 创建任务 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 script_task = PythonOperator( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     task_id=task_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    python_callable=execute_script, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    python_callable=python_callable, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     op_kwargs=op_kwargs, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     retries=TASK_RETRY_CONFIG["retries"], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     retry_delay=timedelta(minutes=TASK_RETRY_CONFIG["retry_delay_minutes"]) 
			 |