Pull to refresh

Не складывайте медленный код в жобу

Level of difficultyEasy
Reading time5 min
Views1.1K

Все разработчики учились на задачах, в которых вопрос производительности либо не стоит в принципе (тудушечка, гостевуха, что там еще принято делать на первом занятии), либо обозначен непосредственно в условиях задачи (алгоритмика, литкоды, злые преподы).

Потом были первые шаги в качестве стажеров/джунов, с соответствующим подбором задач. Чужой код, подсмотренный в пулл-реквестах признанных в команде асов, — тоже, скорее всего, был максимум асинхронным, и никогда параллельным. Так появляются мифы, один из которых — самый вредный, на мой взгляд, в современном мире, где у каждого в пляжном ноутбуке по триста ядер, — «параллельное программирование сложно».

В самой по себе параллельности ничего сверхъестественного нет: надо просто за недельку привыкнуть к тому, что результат получается не сразу, и всё. Проблема в другом: в том бесчисленном количестве костылей, нагроможденных претендующими (на звание неглупых) людьми, чтобы «упростить жизнь медиокра за клавиатурой».

В любой мало-мальской экосистеме обязательно будет такая штука, как «job runner». Чтобы линейный, простой как полено, код — мог иметь дело с длительными вычислениями. Нужен отчёт, а его генерация занимает полчаса? — Нет, мы не сделаем правильно, не поправим наши схемы, не озаботимся триггерами и persistent views, на это у нас нет ни времени, ни денег, мы стартап, поэтому делегируем: пусть весь неэффективный медленный код идёт в жобу!

Я собираюсь высказать и на пальцах обосновать тривиальный тезис: не используйте сторонние библиотеки для выполнения долгоиграющих задач. Кроме тех случаев, когда вам совершенно безразлично, будет ли задача выполнена вообще, а если да — то когда, и как именно.

А если уж используете — используйте с оглядкой.

Правило №1

Никакой бизнес-логики в жобах! Поверьте моему опыту, вы не хотите отвечать на вопрос финдиректора: «Почему вот эти три заказа на общую сумму в триста тугриков прошли, а вон тот, на семь миллионов — подвис?». Жоба — как курьер, которому вы доверяете доставку посылки вашему другу. Если в посылке — пачка сигарет, то переться в такую даль — лень, конечно. Вазу династии Мин — спокойнее довезти самому.

Бизнес-логика обязана выполняться в основном приложении. Разве что генерация отчёта руководству — хорошая задача для отчуждения в жобер, — если вам нравится получать в десять вечера смски от генерального с вопросом: «Где мой отчет?». Бизнес-логика нуждается в полном контроле потока выполнения. Об ошибках нужно узнавать сразу, а не спустя полгода. Я в курсе, что жобу можно обучить писать логи и даже уведомлять об успешном выполнении, но что делать если сообщения о беззаботном выполнении — не поступало?

Правило №2

Никаких retry: true. Это ваш злейший враг, который обязательно откусит вам ногу спустя неделю, месяц, год. Зачем нерадивые программисты используют этот омерзительный во всех отношениях флаг? — Чтобы забыть и спать спокойно, если жоба с первого раза не отработает нормально.

Но давайте чуть притормозим и подумаем: а почему она может не отработать? А главное, почему она вдруг после этого отработает со второй попытки? С пятой? Люди, привыкшие воевать со следствиями вместо обнаружения причин, придумали кучу костылей вокруг неудачного сценария: спиноффы и прочие элегантные подпорки. Но что будет, если прошли сутки, жоба так и не завершилась успешно, и мы запустили следующую? И вот у нас уже есть watchdog, условные операторы «если вчерашняя жоба смогла», куча нерелеватных самой жобе данных для этих проверок и прочий мусор на ровном месте.

Если что-то завершилось с ошибкой — повторная попытка может быть неплохим решением, например, если мы пробовали что-то отправить по HTTP и получили обратно 503. Но максимум одна. Бесконечные попытки долбиться в 503, приключающуюся по вине разработчиков стороннего сервиса потому что хрен знает почему, — заведомо проигрышный сценарий. Но что все-таки делать, если жоба завершилась с ошибкой?

Правило №3

Обработка ошибок должна осуществляться так, как будто весь код выполнялся синхронно.

Вся бизнес-логика — забота основного приложения (я говорил уже, да?). Если вы настаиваете на использовании жобера вместо починки долгоиграющих кусков собственного кода, — так тому и быть. Просто подготовьте своё приложение к тому, что случилась жоба и код в ней нагадил мимо лотка.

Самое глупое, что можно сделать в такой ситуации — попытаться починить проблему изнутри поломавшегося куска кода. Если вы не барон Мюнхгаузен, конечно. Просто создайте внутри приложения сущность, которая будет обрабатывать ошибки из жобы. Верните управление туда, где есть руль, педали и — самое главное — шофёр. В основное приложение.

Правило №4

В жобе не должно быть никаких условных операторов, развесистой логики и прочих атрибутов меню средней руки итальянского ресторана. Обособьте свой долгоиграющий код в отдельную функцию и вызывайте её однострочником. По-крайней мере, будет понятно, что именно сломалось. Все условия нужно проверять до передачи управления в жобер, а не в процессе.

Приходящие в голову якобы исключения «проверить, что всё в порядке» — свидетельства плохого дизайна. Если мы попали в жобу — значит, всё в порядке, можем шуровать. Иначе — вас неизбежно ждёт ад отладки ситуаций типа «почему и как оно вообще выполнилось?».

Правило №5

Это правило, скорее, факультативное, но я решил упомянуть и его тоже. К каждой приключившейся в вашей жизни жобе — надо относиться как к маньяку, знающему, где вы живете. Даже если шансы, что он выберет лично вас среди восьми с лишним миллиардов особей, заполонивших земной шар, — близки к нулю, ожидайте подлости. В отличие от вашего основного кода, эта подлость наверняка останется незамеченной, пока вы не увидите измазанный кровью кухонный нож через дверной глазок.

Если вы поделите на ноль в функции main — приложение просто не запустится. Если этот арифметический просчет случится в какой-нибудь посторонней редкоиспользуемой части приложения — взорвутся логи. Но жоберы стараются вывернуть гетеродин вашего work-life balance по максимуму в приятную сторону. Оно будет пыжиться, стараться, поймает исключение, попытается снова…


Я лично много пользовался жоберами в прошлой жизни. Этому сильно способствовало то, что стандарт de facto в ruby — Sidekiq — написанный умнейшим Майком Перамом — написан действительно хорошо. Код сразу завоевал мои симпатии продуманным и взвешенным подходом к обособлению функций. Sidekiq легко устанавливается, прекрасно работает, не требует никакого внимания, обеспечивает действительно крутую прозрачность. Но это всё еще жобер. Со всеми описанными выше недостатками.

В эликсире стандартом сейчас является Oban. И вот мой вам совет: никогда его не используйте. Сама по себе библиотека — действительно очень крутая. Код — хоть вчера на выставку. Но это всё еще жобер. Который скроет от вас все проблемы вплоть до того момента, когда чинить их может уже и не потребоваться.

Вместо этого — используйте простые процессы (гринтреды, горутины) в сочетании с конечными автоматами с состоянием «в жобе». По завершении — отчитывайтесь о результате ивентом в ваш автомат, а вот он уже пусть занимается разгребанием авгиевых конюшен, если что-то пошло не так. Или переходит в состояние «вышли из жобы», если все завершилось успешно.

Удачного жобинга!

Tags:
Hubs:
+3
Comments15

Articles