Airflow Declarative - как не дать себя опутать
Иван АхлестинИстория создания airflow-declarative восходит к 2017 году (кажется airflow был тогда версии 1.6-1.7), когда я работал в Рамблере (RIP) - мой старший инфраструктурный инженер и куратор Саша Шорин aka kxepal, к тому моменту уже успевший год как отмигрировать все дата-пайплайны с самодельного крона на стероидах на Airflow, столкнулся с несколькими проблемами:
• конечные разработчики пайплайнов зачастую занимались банальной копипастой пайпланов
• конечные таски наследовались и перенаследовались от чего угодно (у Airflow богатая иерархия встроенных операторов), копировались, мутировали. И естественно выживали не самые лучшие и простые решения.
• код операторов идущий из коробки в составе самого airflow - на тот момент был весьма низкого качества - мало тестов, специфичен для конкретной инфраструктуры. К сожалению ментейнеры не особо следили за качеством прикладного кода и принимали все как есть. Это вынуждало реализовывать весь функционал самостоятельно.
• тестирование - для того чтобы написать на таску хотя бы дымовой тест требовалось немалое число усилий, т.к. при использовании API airflow явно-неявно инициализировался рантайм самого airflow (конфиги, база и прочее)
• часть проектов и комманд собралась мигрировать на третий питон (2.7 -> 3.5), при этом нужно было обеспечить существование разных версий питона в рамках единого пайплайна
Посколько сам интерфейс взаимодействия Airflow с кодом оператора довольно примитивен (передача контекста и параметров работы), то сделали генератор дагов на основе YAML описания. Вместо парсинга дага в виде скрипта на питоне задействован независимый парсер на основе библиотеки trafaret.
Сам код операторов избавился от необходимости прямого наследования и связки с Airflow - генератор производит импорт кода и подготовку параметров к нему в рантайме, соответственно работа таких критичных airflow сервисов, как например шедулер не аффектится из-за сломанного описания дага и некорректных импортов. Кроме этого генератор предлагает возможности для построения примитивных циклов, чтобы создать инстансы тасков с различными параметрами.
Что в итоге дал Airflow-declarative в долгой перспективе:
• Мы начали равивать код не оглядываясь на мутирование его API
• Исчезли зависимости от самого Airflow, можем переиспользовать код независимо
• Легкое тестирование - разработчику не нужно думать о Airflow конфигах - он пишет код
• Миграция между версиями Airflow максимально безрисковая - достаточно прогнать тесты генератора airflow-declarative, - это помогло нам уже в авито перейти с Airflow 1.10 до 2.7.1 не меняя код прикладных проектов
• На основе описания в YAML и независимом парсере airflow-declarative - мы реализовали CLI для прямого запуска кода с кастомизацией параметров через него
Из явных минусов:
• Нет вариантов использовать весь функционал Airflow - например Xcom, кастомные параметры запуска. - Для нас на первом месте находится свойство идемпотентности тасок (один и тот же результат при перезапуске-пересчете), так что любой способ ее нарушить скорее зло.
• Пришлось реализовать обертку над Airflow контекстом, чтобы уйти от прямых импортов. - Кажется этот функционал хорошо бы перенести в саму либу, как и генератор CLI
К сожалению старый ментейнер в настоящий момент подзабросил разработку библиотеки (например не влита ветка с поддержкой Airflow 2.* ). Но если будет запрос от сообщества мы опубликуем свой форк.