Найти в Дзене

Async Jobs (Background Jobs

) Если для вас эти слова ничего не говорят, то возможно после этого поста вы сможете нехило улучшить и упростить ваше приложение. Зайдем через проблематику. Буквально в каждом не тривиальном приложении, уже на старте, появляется задача выполнять какие-то задачи асинхронно. Самое простое - отправка писем после регистрации. Почему этого нельзя делать там же где делается регистрация? Отправка письма это почти наверняка взаимодействие с внешним сервисом по api или smtp. А это сеть со всеми вытекающими от задержек до ошибок. Ваши пользователи будут регулярно получать тайматы и ошибку 500. Сразу встает вопрос транзакционности и гарантий. Что в таких ситуациях делать? Первое, что приходит на ум, это выполнять отправку в памяти, но отдельно. Такие механизмы иногда предоставляются самим фреймворком (async в spring boot), либо это можно организовать самому (nodejs, go). Для не критичных вещей, когда нет нагрузок и особых рисков, можно и так, но этот подход быстро упирается в потолок. Что не т

Async Jobs (Background Jobs)

Если для вас эти слова ничего не говорят, то возможно после этого поста вы сможете нехило улучшить и упростить ваше приложение. Зайдем через проблематику.

Буквально в каждом не тривиальном приложении, уже на старте, появляется задача выполнять какие-то задачи асинхронно. Самое простое - отправка писем после регистрации. Почему этого нельзя делать там же где делается регистрация? Отправка письма это почти наверняка взаимодействие с внешним сервисом по api или smtp. А это сеть со всеми вытекающими от задержек до ошибок. Ваши пользователи будут регулярно получать тайматы и ошибку 500. Сразу встает вопрос транзакционности и гарантий. Что в таких ситуациях делать?

Первое, что приходит на ум, это выполнять отправку в памяти, но отдельно. Такие механизмы иногда предоставляются самим фреймворком (async в spring boot), либо это можно организовать самому (nodejs, go). Для не критичных вещей, когда нет нагрузок и особых рисков, можно и так, но этот подход быстро упирается в потолок. Что не так?

• Нет гарантий выполнения. Процесс упал - задача исчезла. Получаем потерянные письма, вебхуки, уведомления. Такое будет происходит и при деплоях и автоматических рестартах и ошибках.

• Нет контроля нагрузки. Если растет потребление ресурсов, то такой подход не маштабируется и начинает мешать основному приложению.

• Нет прозрачности. Вы не видите: что сейчас выполняется, что упало, что зависло, что выполняется слишком долго.

Обычно после этого варианта, сразу переходят к очередям и стримам. А давайте воткнем redis/kafka/rabbitmq и на каком-нибудь задорном языке понапишем отдельных приложений, которые будут хватать эти сообщения и делать всякие задачи от отправки емейлов, до каких-то тяжелых вычислений. Сразу можем добавлять в резюме строчку про построение микросервисной архитектуры.

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

Короче, по середине между двумя этими подходами и затесались background jobs. Это механизм, позволяющий выполнять любые задачи асинхронно в отдельном процессе с персистентностью (а значит гарантиями) и возможностью масштабировать. То есть их можно запускать хоть на другом сервере и в любом количестве экземпляров. Чем это отличается от работы через очереди спросите вы? Отличается и вот в чем. Для начала пример в python (celery). Определение джобы:

# tasks.py

from celery import shared_task

@shared_task

def send_welcome_email(user_id, email):

send_email(email)

Использование:

# registration.py

from tasks import send_welcome_email

def register_user(email):

user = create_user(email)

send_welcome_email.delay(user.id, user.email)

return user

Джобы это код нашего приложения, а не отдельное приложение. На практике мы просто стартуем наше приложение в режиме джоб, когда оно не обрабатывает http запросы, а просто крутится в фоне. Планирование джобы, это отправка сообщений в космос для каких-то консьюмеров, о которых мы ничего не знаем. Джоба это запуск конкретного кода под конкретную задачу, что очень сильно отличает их от очередей. Джобу можно воспринимать просто как функцию, которая, кстати, в тестах часто вызывается вообще синхронно, значительно упрощая инфраструктуру и работу монолита. Данные при этом часто хранятся в redis, а сейчас вообще идет тенденция, чтобы по дефолту хранить джобы в той же базе что и само приложение (что значительно упрощает старт и есть адаптеры). Ну и все это добро поддерживает ретраи, приоритеты и другие механизмы типичные для очередей.

Реализации джоб есть в каждом языке. Какой либой пользуетесь вы?

Ссылки: Телеграм | Youtube | VK