Мы разрабатываем огромное количество сложного программного обеспечения для автоматизации и предприятия, и Workflow для нас — большая и болезненная проблема.
Если это и для вас, я расскажу вам, как писать и организовывать очень сложные процессы в большом масштабе и как сделать так, чтобы они не падали.
А также как сделать внутри процессов таймеры на 30 дней.
И самое главное, как все это вырезать на PHP. Меня зовут Антон Титов .
Я занимаюсь коммерческой разработкой более 17 лет. Я являюсь соавтором Spiral Framework, RoadRunner и Cycle ORM. Основной стек: PHP и Golang. Разговор пойдет о нашей разработке Temporal PHP SDK, который помогает решить все вышеперечисленные сложные проблемы.
Статья получилась большая.
Поэтому я разделил его на теоретическую и практическую части.
Сначала, конечно, теория.
И чтобы ввести вас в курс дела, начну с истории.
Допустим, вас нанял стартап и предложил создать систему доставки пиццы, которую нужно масштабировать на небольшой город. Пиццу необходимо приготовить, затем оформить заказ на доставку и отправить клиенту.
А вы, как опытные разработчики, берете очередь для согласования действий, чтобы она красиво масштабировалась, базу данных, где вы будете хранить состояние, и начинаете писать.
Первая интеграция
Первая интеграция, которую вы делаете — с сервисом Яндекс.
Еда:
Получается, клиент приготовил пиццу, нажал кнопку, кто-то заказал ее в Яндекс.
Еде и получил трек доставки, а пицца отправлена пользователю — все счастливы и довольны.
Чуть позже вы получаете запрос — давайте сделаем не только доставку, но и пошагово покажем пользователю состояние текущего процесса: готовим пиццу, она приготовлена, она сдана на доставку или оно уже в пути:
Вы интегрируетесь с терминалом на кухне и с менеджерами.
Они также будут нажимать кнопки и обновлять статусы.
Это не очень сложная задача.
Вторая интеграция
Чуть позже к вам прибегает директор пиццерии и говорит, что Яндекс.Еда для них дорогая и выгоднее использовать локальный сервис, у которого тоже есть API. Правда API не дает трек-код, а кикает через вебхук и колбэк, но это тоже не проблема.
Просто добавляете пару if, делаете отдельную очередь и точку http:
Третья интеграция
В конце концов, локальный сервис тоже оказывается дорогим, поэтому в соседнем отделе пиццерии двое неизвестных программистов начинают разрабатывать собственный сервис и предлагают вам его реализовать.Однако это тоже пара if-фишек и поначалу все работает. Однако позже выясняется, что сервис разрабатывался на коленках на Perl, поэтому любит зависать и отваливаться.
Но добавляешь пару crontabов для проверки таймаутов, и повторяешь попытку — и система вроде продолжает работать:
Однако возникает новая проблема: повара забывают принимать заказы — в результате клиенты недовольны, а менеджеры ругаются.
Ну а вы добавляете еще один CronJob, который проверяет, что заказ находится на рассмотрении и подготовка очень долгая — и уведомляет об этом поваров.
Аналогичным образом решается ситуация, когда повар забыл достать пиццу из духовки.
В какой-то момент менеджер предлагает вам возможность отменить заказ.
Однако вы не можете отменить заказ на доставку, но можете добавить возможность отмены каким-либо безопасным способом из условия трассировки еще до подготовки.
Например, во время принятия заказа:
Похоже, мы закончили!
В результате получается система, описывающая бизнес-процесс или Workflow по приготовлению и доставке пиццы.На диаграмме видно, что она сильно перемешана не только с бизнес-задачой, но и со структурной логикой — обратными вызовами, таймаутами, повторами и так далее.
Можно написать такую систему в лоб — взять немного редиски, немного RabbitMQ, добавить пару кронных задач и как-то склеить, но в итоге у вас получится монстр с кучей проблем:
Масштабировать его будет очень сложно.
Поэтому, если ту компанию купит крупный холдинг и скажет: «Давайте доставлять не 100 пицц в день, а 10 тысяч в час», то вам придется все переписывать с нуля.
Это все Workflow, а система, которая передает данные между этапами, называется оркестровкой.
Давайте поговорим о рабочем процессе и оркестрации.
Чтобы объяснить, что здесь можно сделать, давайте сначала немного взглянем на то, что такое Workflow – более простыми словами.
Очень часто его представляют в виде схемы со стрелками и набором шагов.
Тогда вы сможете наглядно увидеть, как происходит согласование действий между внешними и внутренними задачами.
Они могут быть с API или ответами пользователей, но в любом случае это программа для синхронизации этих шагов синхронно или асинхронно:
Будет неудобно, если мы напишем систему доставки пиццы, а потом, чтобы добавить новый шаг, придется все это переписывать.
Поэтому мне очень хочется иметь инструмент, который позволит мне делать это легко и просто, не нарушая существующую бизнес-логику.
Концептуально это основная цель Workflow. Очень важным свойством любого Workflow в реальном мире является, во-первых, получение влияние внешних событий , а во-вторых, быть продлен во времени .
В любой задаче, будь то логистика, система доставки пиццы или подъем серверов, у вас не возникнет ситуация, когда все задачи выполняются мгновенно.
Некоторые из них займут секунду, некоторые — минуту, другие — пару дней, а некоторые даже несколько месяцев.
Поэтому никаких ограничений здесь быть не должно.
Также необходимо учитывать, что бизнес-процессы не живут в вакууме.
Как только мы что-то запускаем, всегда находится человек, который предложит что-то улучшить.
Например, возможность добавить перец в пиццу после оформления заказа.
Поэтому нам нужна система, которая позволит влиять на состояние бизнес-процесса.
Возможно, двумя наиболее важными моментами, которые необходимо понимать с точки зрения масштаба, являются: наблюдаемое состояние И устойчивое состояние.
Наблюдаемое состояние
Это возможность понять, где мы сейчас находимся в нашем бизнес-процессе.Ведь не очень удобно, если при заказе пиццы приходится гадать, приедет она к нам или нет, и если приедет, то когда.
Поэтому хотелось бы иметь возможность поиска по Workflow: по состоянию, то есть по стадии выполнения.
И наконец, если вы работали с крупным предприятием, то знаете, что есть очень важное требование – журнал аудита.
Нам нужно понять, какой шаг в какое время был сделан, как и когда он мог оказаться неудачным и как его оптимизировать в будущем.
Устойчивое состояние
Даже если у нас сгорел сервер, вышла из строя база данных и отключилась сетевая карта, мы все равно хотим быть уверены, что после перезагрузки система продолжит работать с нужной точки.В противном случае в Workflow нет смысла.
Чтобы достичь устойчивого состояния или отказоустойчивости, нам необходимо решить несколько проблем.
И сначала убедитесь, что ошибки в коде и бизнес-процессе не потеряны.
Очень неприятно, когда что-то падает и мы не знаем, что именно.
Логов нет, системы нет, а у нас служба доставки дала сбой или повар какой-то странный? В идеале вы хотите понять всю историю ошибки.
Например, доставка не пришла, потому что пицца была неправильной.
А пицца неправильная, потому что служба оформления заказа не удалась, добавила неправильный ингредиент, и повар не смог приготовить пиццу.
Если мы делаем большие, сложные — особенно если они распределенные — системы с кучей микросервисов, то важно понимать, как они связаны друг с другом.
Как происходит распространение ошибок или распределенная трассировка стека ошибок.
Естественно, поскольку мы пишем процессы для реального мира, все равно будут проблемы, когда отвалится внешнее API, микросервис или что-то просто зависнет. Поэтому важно иметь подсистему таймаутов.
Если мы отправили задание на кухню, но за полчаса ничего не произошло, то давайте выясним, что там произошло.
Также необходимо иметь систему ретрея — в идеале с бэкоффом, чтобы в случае отвала API можно было потихоньку попытаться до него достучаться.
Рабочий процесс – где он используется?
- распределенных вычислений;
- финансовые операции;
- логистика, инвентарь;
- синхронизация внешних систем;
- накопительная рассылка уведомлений;
- пользовательские кассы и корзины покупок;
- документооборот;
- управление инфраструктурой;
- обработка файлов;
- мониторинг, CI/CD;
- просто чтобы не упал.
И если вы начнете видеть Workflow и поймете, что это закономерность, то выкинуть ее из головы будет очень сложно.
Варианты реализации
Мы рассмотрели пример, у нас даже есть какая-то теоретическая база.Давайте подумаем, как это можно реализовать.
Напишем об очередях и базах данных!
Первый вариант я уже описал — пишем в лоб, поднимая какую-то систему очередей для балансировки задач.Для масштабирования мы поднимаем базу данных, чтобы понять, на каком этапе процесса мы сейчас находимся.
Проблема в том, что для реализации отказоустойчивости этой системы нужно очень постараться:
Транзакционность будет вашей самой большой проблемой при масштабировании, потому что всегда будет ситуация, когда вы добавили значение в базу данных, но очередь его не приняла, или наоборот. В итоге вы получаете сломанное состояние, полностью замороженную систему и непонятно, что с этим делать.
Может, на Кафке?
Если вы более предприимчивы, вы можете попробовать Kafka:Kafka — это система, управляемая событиями, она гарантирует определенный транзакционный характер журналирования и хорошо масштабируется.
Но, скорее всего, вам придется писать много кода, потому что согласование различных разделов и конвейеров — дело нетривиальное, отнимающее много времени.
Однако большое количество крупных стартапов используют Kafka для координации своих задач, и это тоже допустимый вариант.
Рабочий процесс - ну тогда декларативно!
Мы, наверное, все ленивые разработчики, поэтому давайте просто найдем готовый инструмент. Скорее всего, это будет декларативная реализация Workflow:Это будет некий JSON, описывающий набор шагов и переход между ними.
BPMN в лучшем случае.
Например, Apache Airflow или Camunda, где мы можем рисовать диаграммы, передавать данные между ними и таким образом координировать нашу систему.
Вариаций декларативных Workflow очень много, есть даже отдельный репозиторий assemble_workflow. Но все они имеют множество ограничений.
Рабочий процесс — ограничения DAG
Ограничения в основном связаны с тем, что это декларативная система:- запеченный граф (сложно создавать динамические ветки);
- конечный автомат, полный ограничений;
- каждый тянет в свою сторону;
- дорого использовать для чего-то небольшого;
- сложно интегрироваться в существующий код;
- максимальный размер графа ограничен;
- возможности картографирования ограничены;
- Трудно управлять глобальными данными процесса.
Соответственно нет динамики.
Для небольших задач этого добиться очень сложно.
Ну и зачем затягивать визуальный BPMN, чтобы заказать пиццу? Легче написать это на колене.
Ввиду того, что все декларативно, передача данных между шагами будет осуществляться только по тем примитивам отображения и вариациям, которые доступны в этом движке.
Если вам нужно больше кастомного маппинга, то напишите авторам и надейтесь, что они его добавят. Есть еще много проблем.
Например, не существует общего стандарта, поэтому, если вы изучили Netflix Conductor, а затем перешли на Apache Airflow, изучите его еще раз.
У вас появятся новые примитивы, новые отображения, и двигаться будет очень сложно.
И всё очень печально: придётся писать самому — это очень долго, дорого, сложно — а крайних случаев миллион.
У готовых движков много ограничений, причем половина из них платные.
И почти везде требуется DSL. У нас много корпоративного программного обеспечения, и Workflow для нас — старая боль.
Поэтому мы серьезно подошли к проблеме, долго искали и наконец нашли интересный продукт. Убер Каденс — это движок рабочего процесса, причем очень интересный:
- описание Workflow по коду;
- вы можете создать свой собственный DSL;
- изоляция данных;
- бесконечный масштаб;
- Ядро Голанга.
Но, кроме этого, это также гарантирует, что система не выйдет из строя.
Поскольку движок императивный, то есть написанный в вашем коде, вы можете взять свой готовый DSL, переписать его в Temporal и поставить прямо поверх него.
Многие пользователи этого движка так делают, это реальный вариант использования.
Uber Cadence очень хорошо масштабируется линейно, потому что Uber — это очень большая система, которая обслуживает множество городов в разных странах.
Он используется под их капотом в качестве основного механизма координации всех финансовых транзакций.
Большим бонусом для нас стала возможность использовать ядро Golang и Golang SDK. Поскольку у нас много продуктов, написанных на Golang, в частности, РоудРаннер .
Но все оказалось еще интереснее.
Авторы Uber Cadence открыли отдельный стартап, получили инвестиции и дали ему название Временной , и все это было лицензировано по лицензии MIT. К тому же это были бывшие россияне, поэтому нам было проще общаться с ними по вопросам интеграции и разработки API. Для нас это был полный беспроигрышный вариант — масштабируемая система MIT, которую можно собрать дома, описывает Workflow в коде без всякого DSL, а также можно общаться на русском языке.
А на что способен Temporal PHP SDK, мы посмотрим в следующей, более практической части.
Конференция PHP Россия 2022 это отличное место, чтобы поделиться своим опытом с сообществом.Теги: #Алгоритмы #программирование #отказоустойчивость #оркестрация #Go #php #temporal #workflow #temporal php sdk #Uber Cadence #enterpriseОн пройдет 12 и 13 сентября в Москве, в отеле Radisson SAS Славянская.
Фокус: развитие экосистемы (сам PHP, стандарты, фреймворки, библиотеки, OpenSource); опыт крупных компаний по построению сложных проектов на PHP и лучшие практики.
И, конечно же, темы ежедневного развития.
Заявки на выступления принимаются до 25 мая.
Расходы на проезд и проживание спикеров покрываются.
Все подробности на Веб-сайт .
-
Выбор Инструментов Управления Ит-Услугами
19 Oct, 24 -
О Чем Пользователи Не Напишут Вам В Отзывах
19 Oct, 24 -
Настоящие Программисты
19 Oct, 24