[英]Airflow Sensor - timeout
tl; 博士,问题框架:
假设我有一个timeout = 24*60*60
的传感器。 由于连接偶尔会超时,因此必须允许retries
。 如果传感器现在重试,则timeout
变量将应用于初始为24*60*60
的每次新尝试,因此,任务不会按预期在 24 小时后超时。
问题:
有没有办法限制任务的最大时间——比如元超时?
气流版本: 1.10.14
遍历:
BASE_DIR = "/some/base/dir/"
FILE_NAME = "some_file.xlsx"
VOL_BASE_DIR = "/some/mounted/vol/"
default_args = {
"owner": "airflow",
"depends_on_past": False,
"start_date": "2020-11-01",
"retries": 2,
"retry_delay": timedelta(minutes=5),
}
dag = DAG(
"supplier",
default_args=default_args,
description="ETL Process for Supplier",
schedule_interval=None,
catchup=False,
max_active_runs=1,
)
file_sensor = FileSensor(
task_id="file_sensor",
poke_interval=60*60,
timeout=24*60*60,
retries=4,
mode="reschedule",
filepath=os.path.join(BASE_DIR,FILE_NAME)
fs_conn_id='conn_filesensor',
dag=dag,
)
clean_docker_vol = InitCleanProcFolderOperator(
task_id="clean_docker_vol",
folder=VOL_BASE_DIR,
dag=dag,
)
....
此 DAG 应运行并检查文件是否存在。 如果它存在,它应该继续。 有时,由于提供的文件太晚(或者说,连接错误),传感器任务可能会被重新安排。 dag 的最大整体“运行时间”不应超过 24 小时。 但是,由于重试,如果任务失败并且正在重新安排,时间确实会超过 24 小时超时。
例子:
因为我需要允许重试,所以没有将重试设置为 0 来避免这种行为的选项。 我宁愿寻找 airflow 的元超时变量,提示如何在相关类或任何其他解决方法中实现它。
非常感谢。
您可以使用poke_interval
参数来配置预定义超时内的戳频率。 像这样的东西: MySensor(..., retries=0, timeout=24*60*60, poke_interval=60*60)
。 在此示例中,传感器将每小时戳一次,如果它在一天内不成功,它将失败。
我实施了一个相当老套的解决方案,但对我有用。
def _apply_meta_timeout(self,context):
if not self.meta_task_timeout:
return None
elif self.meta_task_timeout and self.retries == 0:
raise ValueError("'Meta_task_timeout' cannot be applied if 'retries' are set to 0. Use 'timeout' instead.")
if isinstance(self.meta_task_timeout,datetime.timedelta):
self.meta_task_timeout = meta_task_timeout.seconds
if not isinstance(self.meta_task_timeout,(int,float)):
raise ValueError("Cannot covert 'meta_task_timeout' to type(int) or type(float).")
if self.meta_task_timeout < self.timeout:
raise ValueError("'meta_task_timeout' cannot be less than 'timeout' variable.")
logging.info(f"Get current dagrun params: {context['ti'].task_id}, {context['ti'].dag_id}, {context['ti'].execution_date}, {context['ti'].try_number}" )
pg_hook = PostgresHook(postgres_conn_id="airflow-metadata-db")
pg_cur = pg_hook.get_cursor()
if not context['ti'].try_number == 1:
try:
query = f"""
select start_date from task_fail
where task_id='{context['ti'].task_id}'
and dag_id='{context['ti'].dag_id}'
and execution_date ='{context['ti'].execution_date}'
order by start_date asc
LIMIT 1;"""
pg_cur.execute(query)
init_start_timestamp = pg_cur.fetchone()[0] #.isoformat()
except Exception as e:
raise ConnectionError("Connection failed with error: " + str(e) )
finally:
pg_cur.close(), pg_hook.get_conn().close()
else:
init_start_timestamp = context['ti'].start_date #.isoformat()
logging.info(f"Initial dag startup: {init_start_timestamp}")
if (timezone.utcnow() - init_start_timestamp).total_seconds() > self.meta_task_timeout:
if self.soft_fail:
self._do_skip_downstream_tasks(context)
raise AirflowSkipException('Snap. Maximal task runtime is UP.')
logging.info(f"Time left until 'meta_time_out' applies: {self.meta_task_timeout - (timezone.utcnow() - init_start_timestamp).total_seconds()} second(s).
def poke(self, context):
...
...
# check for meta-time-out
self._apply_meta_timeout(context)
添加 airflow 数据库连接为:airflow airflow-metadata-db
使用附加参数调用传感器操作员:
dummy_sensor = FileSensor(
task_id="file_sensor",
remote_path=os.path.join(REMOTE_INPUT_PATH, REMOTE_INPUT_FILE),
do_xcom_push=False,
timeout= 60,
retries=2,
mode="reschedule",
meta_task_timeout=5*60,
soft_fail=True,
#context=True,
)
必须应用此解决方法的主要问题是 airflow 似乎覆盖了每个单独的 DAG-try 的初始start_date 。
请随时添加任何改进建议。 谢谢
这就是为什么我们对传感器使用 task_retries 和 retry_delay 而不是使用 poke_interval 和 timeout。 重试完全达到你想要做的。 在您的任务定义中,使用
retries: 24,
retry_delay: 60*60
代替
poke_interval=60*60,
timeout=24*60*60,
retries=4,
顺便说一句,你应该添加mode="reschedule,
这样你的传感器就不会在整个执行时间内占用一个槽(在这里,你的任务在 24 小时内使用整个槽,大部分时间都在休眠)。
每个 dag 运行的开始日期不应被start_date
覆盖,并且应该通过{{ ds }}
(这是数据间隔的开始)或{{ data_interval_end }}
(参见Airflow 文档)获得。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.