Как запускать фоновые задачи в веб-приложении: очереди, планировщики и cron
Чтобы запускать фоновые задачи в веб-приложении, сначала разделите работу на два вида. Запускаемые по событию задачи (отправить письмо-приветствие, обработать загрузку) можно сохранить в очередь задач, часто это таблица в базе данных, а обработчик выполнит их с повторами. Плановые задачи (ночной отчёт, напоминания каждые 15 минут) нуждаются в чём-то, что срабатывает по расписанию: функция cron на хостинге или внешний планировщик, который вызывает защищённую конечную точку в вашем приложении. Всегда делайте задачи безопасными для повторного запуска, фиксируйте сбои и никогда не полагайтесь на таймер внутри сервера, который может уснуть или перезапуститься.
В этом руководстве объясняются варианты, когда какой подходит и как их настроить с ИИ-конструктором приложений, в том числе на хостингах, которые масштабируются до нуля.
Что считается фоновой задачей
Всё медленное, ненадёжное или не нужное для немедленного ответа пользователю:
- Отправка писем, уведомлений и чеков
- Обработка изображений, перекодирование видео, генерация PDF
- Вызовы медленных сторонних API, включая AI-модели для долгих задач
- Импорт или синхронизация данных из другой системы
- Ночная очистка, отчёты и напоминания
Если делать это внутри запроса, страницы будут тормозить и ломаться: если почтовый провайдер недоступен, регистрация пользователя упадёт. Перенос в фон означает, что пользователь получает мгновенный ответ, а задачу можно повторить.
Варианты
| Вариант | Как работает | Плюсы | Минусы |
|---|---|---|---|
| Выполнить в том же процессе без ожидания | Ответить, затем продолжить работу на сервере | Без настройки | Теряется, если сервер остановится; нет повторов |
Таймер внутри процесса (setInterval, setTimeout) | Таймер в работающем сервере | Очень просто | Не срабатывает, пока сервер спит; дублируется при нескольких копиях |
| Очередь в базе данных | Задачи сохраняются как строки; обработчик забирает и выполняет их | Использует вашу базу; надёжно; легко проверить | Вы сами реализуете повторы и блокировки; нужно что-то, что запустит обработчик |
| Выделенная очередь (на базе Redis или управляемая) | Сервис очереди и обработчики | Зрелые функции повторов и расписания | Ещё один сервис для запуска и оплаты |
| Хостинговый сервис задач или workflow | Сторонний сервис вызывает ваши конечные точки с повторами и расписанием | Расписание и повторы обеспечиваются за вас | Зависимость от вендора; отдельный аккаунт и ключ |
| Внешний планировщик, вызывающий конечную точку | Таймер где-то ещё посылает HTTP-запрос по расписанию | Работает на любом хостинге, включая масштабируемый до нуля | Минимальные интервалы и задержки; нужно защищать конечную точку |
| Встроенный cron хостинга | Платформа запускает команду по расписанию | Просто там, где есть | Не каждый хостинг его предоставляет |
Единого правильного ответа нет. Небольшому приложению часто достаточно очереди в базе данных и внешнего планировщика.
Почему хостинги, масштабируемые до нуля, меняют картину
Многие современные хостинги усыпляют ваше приложение, когда им никто не пользуется, и будят его при следующем запросе. Это экономит деньги, но спящий сервер не выполняет код: таймеры не срабатывают, обработчики не опрашивают очередь. На таких хостингах плановая работа должна начинаться с входящего запроса, и проще всего источником такого запроса стал внешний планировщик. Каждый вызов будит приложение (и часто его базу), поэтому вызов каждую минуту стоит дороже, чем каждые 15 минут. Выбирайте самое редкое расписание, которое удовлетворяет потребность.
Шаблон 1: очередь задач в базе данных
Для задач, запускаемых по событию:
- Создайте таблицу
jobs: тип, полезная нагрузка (JSON), статус (pending,running,done,failed), attempts, run_after, last_error, временные метки. - Когда что-то происходит, вставьте строку задачи в той же транзакции, что и изменение, которое её вызвало, — так они либо успешны вместе, либо падают вместе.
- Обработчик берёт задачи, которые пришло время выполнить, помечает их
running, выполняет работу и помечаетdone. - При сбое увеличьте
attempts, поставьтеrun_afterпозже (например, через 1, 5, затем 30 минут) и сохраните ошибку. После максимума отметьте задачу какfailedи предупредите кого-то.
Если одновременно может работать несколько обработчиков, задачи нужно забирать безопасно. В Postgres SELECT ... FOR UPDATE SKIP LOCKED позволяет каждому обработчику забирать разные строки, не конфликтуя.
Что запускает обработчик? На постоянно работающем сервере — цикл в отдельном процессе. На хостинге, масштабируемом до нуля, плановая конечная точка из шаблона 2 может обрабатывать пакет задач, которые пришло время выполнить, при каждом вызове.
Шаблон 2: внешний планировщик, вызывающий ваше приложение
Для плановых задач:
- Добавьте конечную точку, например
POST /api/cron/send-reminders. - Защитите её: требуйте секретный токен в заголовке, хранящийся как секрет на обеих сторонах, и отклоняйте всё остальное.
- Сделайте её идемпотентной: повторный запуск в ту же минуту не должен отправить два напоминания. Записывайте, что уже отправлено.
- Держите каждый вызов коротким: обрабатывайте пакет (скажем, 100 элементов), а следующий вызов подберёт остальное.
- Направьте на неё планировщик.
Варианты планировщика:
- Запланированные workflow в GitHub Actions. Бесплатно в пределах лимитов использования GitHub. По документации GitHub на сентябрь 2026 года, минимальный интервал — раз в 5 минут, запуски могут задерживаться в часы пик (особенно в начале каждого часа), расписания по умолчанию используют UTC, а запланированные workflow в публичном репозитории отключаются после 60 дней без активности репозитория.
- Хостинговые сервисы cron. Существует много сервисов, единственная задача которых — вызывать URL по расписанию. Проверьте надёжность, минимальный интервал и оповещения, прежде чем на них полагаться.
- Планировщик вашего облачного провайдера. Если вы уже используете крупного облачного провайдера, у него будет управляемый планировщик, который может вызывать HTTPS-конечную точку.
- Хостинговый сервис задач или workflow. Они совмещают расписание, очереди и повторы и вызывают ваши конечные точки для каждого шага. Сравните цены и лимиты на сайтах вендоров.
Шаблон 3: пусть это сделает провайдер
Иногда лучшая фоновая задача — её вовсе нет:
- Платежи. Stripe повторяет неудачные списания по подпискам и отправляет вебхуки; вы реагируете, а не опрашиваете. См. что такое вебхук.
- Email. Провайдеры ставят доставку в очередь и повторяют её, когда вы передали им сообщение.
- Массовая работа с AI. OpenAI и Anthropic предлагают пакетные API для несрочных запросов, которые вы отправляете и забираете позже.
Промпты для ИИ-конструктора
Для очереди:
Добавь фоновую очередь задач, используя таблицу jobs в нашей базе данных (тип, JSON-полезная нагрузка, статус, attempts, run_after, last_error). Когда пользователь регистрируется, вставляй задачу send_welcome_email в той же транзакции вместо отправки письма сразу. Добавь функцию processJobs(limit), которая забирает задачи, готовые к выполнению, через SELECT ... FOR UPDATE SKIP LOCKED, выполняет их и повторяет сбои через 1, 5 и 30 минут, помечая как failed после 4 попыток.
Для плановой задачи:
Добавь POST /api/cron/tick, защищённый bearer-токеном из секрета CRON_SECRET; отклоняй любой запрос без него. Каждый вызов запускает processJobs(100) и отправляет напоминания о бронированиях, которые должны уйти в ближайшие 24 часа и ещё не отправлены; отправленные напоминания записывай, чтобы ничего не ушло дважды. Верни JSON-сводку того, что выполнилось. Затем напиши workflow GitHub Actions, который вызывает эту конечную точку каждые 15 минут, читая URL и токен из секретов репозитория.
Частые ошибки
- Опора на
setInterval. Он молча останавливается, когда сервер засыпает или перезапускается, и дублируется, когда работают две копии. - Незащищённая cron-конечная точка. Любой, кто её найдёт, может запустить ваши задачи или ваш счёт за email.
- Задачи, которые не идемпотентны. Повторы и дублирующие вызовы планировщика будут происходить. Проектируйте с учётом этого.
- Нет видимости сбоев. Задача, которая молча падает неделю, хуже той, которая падает громко. Логируйте ошибки и предупреждайте о повторных сбоях.
- Долгие запуски в одном запросе. Запросы истекают по таймауту. Обрабатывайте пакетами.
- Слишком частое расписание. Каждый вызов на хостинге, масштабируемом до нуля, будит и оплачивает приложение. Подгоняйте интервал под реальную потребность.
- Часовые пояса. «9 утра» означает разное для вашего планировщика (часто UTC) и для пользователей. Храните время в UTC и переводите для каждого пользователя.
- Секреты в файле workflow. Храните токены в хранилище секретов планировщика. См. как хранить ключи API в безопасности.
Чек-лист
- Медленная работа вынесена из пользовательских запросов
- Задачи хранятся надёжно, а не только в памяти
- Повторы с возрастающими задержками и максимумом
- Каждую задачу безопасно запускать дважды
- Плановая конечная точка защищена секретным токеном
- Каждый запуск обрабатывает ограниченный пакет
- Сбои задач видны, есть оповещения
- Интервал расписания выбран с учётом стоимости хостинга
- Время хранится в UTC
Фоновые задачи в Mythex
Документация Mythex не описывает плановые или cron-задачи, а опубликованные приложения и их базы данных засыпают при простое и просыпаются при следующем запросе (см. Hosting limits). Поэтому не полагайтесь на таймеры внутри приложения. Работает подход, описанный выше: попросите агента создать таблицу задач и конечную точку, защищённую токеном, а затем направьте внешний планировщик на опубликованный URL. Храните токен как секрет проекта и учитывайте, что каждое пробуждение расходует кредиты за время, пока приложение и база активны, поэтому выберите разумный интервал. Если вашему приложению для этого нужен бэкенд API, бэкенд REST API — хорошая отправная точка, а как создать REST API описывает проектирование конечных точек. Если ядро вашего продукта — постоянно работающие воркеры или боты, может подойти хостинг, созданный для долгих процессов.
Вопросы
Что такое фоновая задача?
Фоновая задача — это работа приложения вне запроса, который ждёт пользователь, например отправка писем, обработка изображений, генерация отчётов или синхронизация данных. Пользователь получает быстрый ответ, а задача выполняется отдельно и может быть повторена при сбое.
Как запустить плановую задачу, если у хостинга нет cron?
Добавьте защищённую конечную точку, которая делает работу, и пусть внешний планировщик вызывает её по расписанию. Варианты: запланированный workflow в GitHub Actions, внешний сервис cron или планировщик вашего облачного провайдера. Защитите конечную точку секретным токеном.
Можно ли использовать setInterval или setTimeout для плановых задач?
Только для небольших, некритичных задач на сервере, который всегда работает. Если сервер перезапустится, масштабируется до нуля или запущено несколько копий, таймеры теряются или срабатывают больше одного раза. Храните запланированную работу в базе данных или используйте планировщик.
Поддерживает ли Mythex cron-задачи?
Документация Mythex не описывает плановые или cron-задачи, а опубликованные приложения засыпают при простое. Надёжный подход — внешний планировщик, который вызывает защищённую конечную точку вашего приложения; она будит приложение и выполняет работу.