"""
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)

