如何抑制Glue作业中Redshift临时表不存在的异常通知?
问题解决:Glue写入Redshift时临时表不存在的异常消除
核心原因
你的推测完全正确:Glue的write_dynamic_frame.from_jdbc_conf在执行preactions之前,会先校验dbtable指定的表是否存在,第一次运行时表尚未创建,底层JDBC驱动会抛出表不存在的异常。虽然后续preactions会创建表并完成数据写入,但该异常会留在日志中,且Python的try-except无法捕获(因为异常来自Glue底层JDBC操作,而非Python代码层面)。
解决方案
1. 提前独立创建临时表
在调用from_jdbc_conf之前,先通过Redshift Data API执行表创建语句,确保写入时表已存在。
示例代码:
import boto3 import time # 初始化Redshift Data客户端 redshift_data = boto3.client('redshift-data') # 构建创建临时表的SQL create_table_sql = f"CREATE TABLE IF NOT EXISTS staging_table (LIKE {_redshift_db_info['TargetTable']})" # 执行SQL语句 execute_response = redshift_data.execute_statement( ClusterIdentifier="你的Redshift集群ID", Database="some_db", IamRoleArn=REDSHIFT_JDBC_IAM, Sql=create_table_sql ) # 等待SQL执行完成 statement_id = execute_response['Id'] while True: status = redshift_data.describe_statement(Id=statement_id)['Status'] if status in ["FINISHED", "FAILED", "ABORTED"]: if status == "FAILED": raise Exception(f"创建临时表失败:{redshift_data.describe_statement(Id=statement_id)['Error']}") break time.sleep(2) # 执行Glue写入操作 from_jdbc_conf( frame=df, catalog_connection=CATALOG_CONNECTION, connection_options=jdbc_options, transformation_ctx="write_dynamic_frame", redshift_tmp_dir=S3_BUCKET_REDSHIFT_TEMP_DIR )
2. 调整日志过滤规则
如果不想修改代码逻辑,可以通过CloudWatch日志过滤掉该异常:
- 进入Glue作业对应的CloudWatch日志组
- 添加过滤模式,精准匹配表不存在的异常文本(例如
"Table does not exist"),将其设置为忽略 - 注意:过滤规则要精准,避免误屏蔽其他重要错误日志
替代流程方案
方案A:使用Spark原生JDBC写入
将Glue DynamicFrame转换为Spark DataFrame,直接调用Spark的JDBC写入API,部分场景下Spark会优先执行preActions再校验表存在:
# 转换为Spark DataFrame spark_df = df.toDF() # 构建JDBC参数 jdbc_url = "jdbc:redshift://你的Redshift集群端点:5439/some_db" spark_jdbc_options = { "dbtable": "staging_table", "preActions": f"CREATE TABLE IF NOT EXISTS staging_table (LIKE {_redshift_db_info['TargetTable']})", "postActions": query_to_insert_from_stageing_table_to_target_table, "aws_iam_role": REDSHIFT_JDBC_IAM, "tempdir": S3_BUCKET_REDSHIFT_TEMP_DIR, "driver": "com.amazon.redshift.jdbc42.Driver" } # 执行写入 spark_df.write \ .format("jdbc") \ .options(**spark_jdbc_options) \ .mode("append") \ .save()
方案B:改用固定临时表+截断逻辑
提前在Redshift中创建好staging_table结构,每次写入前用preactions截断表,而非动态创建:
jdbc_options = { "database": "some_db", "dbtable": "staging_table", "preactions": "TRUNCATE TABLE staging_table;", "postactions": query_to_insert_from_stageing_table_to_target_table, "aws_iam_role": REDSHIFT_JDBC_IAM }
这种方式彻底避免了表不存在的校验问题,适合重复使用同一临时表的场景。
内容的提问来源于stack exchange,提问作者Nick Clayne
相关产品推荐
相关产品推荐

