109 lines
4.2 KiB
Python
109 lines
4.2 KiB
Python
"""
|
|
DAG для демонстрации обработки ошибок в Airflow
|
|
Уровень: Продвинутый
|
|
"""
|
|
from datetime import datetime, timedelta
|
|
from airflow import DAG
|
|
from airflow.operators.python import PythonOperator
|
|
from airflow.operators.dummy import DummyOperator
|
|
from airflow.models.baseoperator import chain
|
|
import random
|
|
|
|
# Определение DAG
|
|
default_args = {
|
|
'owner': 'student',
|
|
'depends_on_past': False,
|
|
'start_date': datetime(2023, 1, 1),
|
|
'email_on_failure': False, # Отключаем email уведомления для простоты
|
|
'email_on_retry': False,
|
|
'retries': 3, # Количество попыток при ошибке
|
|
'retry_delay': timedelta(seconds=10) # Задержка между попытками
|
|
}
|
|
|
|
dag = DAG(
|
|
'error_handling_dag',
|
|
default_args=default_args,
|
|
description='DAG для изучения обработки ошибок в Airflow',
|
|
schedule_interval=timedelta(days=1),
|
|
catchup=False,
|
|
tags=['educational', 'error_handling', 'advanced']
|
|
)
|
|
|
|
def unreliable_task():
|
|
"""Задача, которая может завершиться с ошибкой"""
|
|
# В реальном сценарии это может быть задача, зависящая от внешних факторов
|
|
# Для учебных целей случайным образом генерируем ошибку
|
|
if random.random() < 0.3: # 30% вероятность ошибки
|
|
print("Ошибка: задача не выполнена успешно!")
|
|
raise Exception("Случайная ошибка в задаче")
|
|
|
|
print("Задача выполнена успешно!")
|
|
return "Задача выполнена"
|
|
|
|
def success_handler():
|
|
"""Обработчик успешного выполнения"""
|
|
print("Поздравляем! Все задачи выполнены успешно!")
|
|
return "Успешно завершено"
|
|
|
|
def failure_handler():
|
|
"""Обработчик ошибок"""
|
|
print("Одна или несколько задач завершились с ошибкой!")
|
|
print("Проверьте логи для получения дополнительной информации")
|
|
return "Ошибка обработана"
|
|
|
|
def retry_task():
|
|
"""Задача с механизмом повторных попыток"""
|
|
# Имитируем задачу, которая может завершиться с ошибкой, но со временем исправляется
|
|
import time
|
|
time.sleep(2) # Имитация работы
|
|
|
|
# С вероятностью 50% задача завершится с ошибкой
|
|
if random.random() < 0.5:
|
|
print("Ошибка в retry_task!")
|
|
raise Exception("Ошибка в задаче с повторными попытками")
|
|
|
|
print("retry_task выполнена успешно!")
|
|
return "retry_task завершена"
|
|
|
|
# Определение задач
|
|
start_task = DummyOperator(
|
|
task_id='start_task',
|
|
dag=dag
|
|
)
|
|
|
|
unreliable_task = PythonOperator(
|
|
task_id='unreliable_task',
|
|
python_callable=unreliable_task,
|
|
dag=dag
|
|
)
|
|
|
|
retry_task = PythonOperator(
|
|
task_id='retry_task',
|
|
python_callable=retry_task,
|
|
dag=dag
|
|
)
|
|
|
|
success_handler_task = PythonOperator(
|
|
task_id='success_handler',
|
|
python_callable=success_handler,
|
|
trigger_rule='all_success', # Выполняется только если все предыдущие задачи успешны
|
|
dag=dag
|
|
)
|
|
|
|
failure_handler_task = PythonOperator(
|
|
task_id='failure_handler',
|
|
python_callable=failure_handler,
|
|
trigger_rule='one_failed', # Выполняется если хотя бы одна предыдущая задача завершилась с ошибкой
|
|
dag=dag
|
|
)
|
|
|
|
end_task = DummyOperator(
|
|
task_id='end_task',
|
|
dag=dag
|
|
)
|
|
|
|
# Установка зависимостей
|
|
# Используем chain, чтобы наглядно показать ученикам построение ветвящихся зависимостей без ручного перечисления операторов.
|
|
chain(start_task, [unreliable_task, retry_task], [success_handler_task, failure_handler_task], end_task)
|
|
|