#python #cron #flask #apscheduler
Вопрос:
Я создаю веб-сайт, который предоставляет некоторую информацию посетителям. Эта информация агрегируется в фоновом режиме путем опроса пары внешних API каждые 5 секунд. Сейчас у меня все работает так, что я использую задания APScheduler. Сначала я предпочел APScheduler, потому что он упрощает перенос всей системы (так как мне не нужно устанавливать задания cron на новой машине). Я запускаю функции опроса следующим образом:
from apscheduler.scheduler import Scheduler
@app.before_first_request
def initialize():
apsched = Scheduler()
apsched.start()
apsched.add_interval_job(checkFirstAPI, seconds=5)
apsched.add_interval_job(checkSecondAPI, seconds=5)
apsched.add_interval_job(checkThirdAPI, seconds=5)
Это вроде как работает, но с этим есть некоторые проблемы:
- Для начала это означает, что интервальные задания выполняются вне контекста колбы. До сих пор это не было большой проблемой, но при сбое вызова конечной точки я хочу, чтобы система отправила мне электронное письмо (со словами «привет, вызов API X не удался»). Однако, поскольку он не запускается в контексте Flask, он жалуется, что flask-mail не может быть выполнен (
RuntimeError('working outside of application context')
). - Во-вторых, мне интересно, как это будет вести себя, когда я больше не буду использовать встроенный отладочный сервер Flask, а рабочий сервер, скажем, с 4 рабочими. Тогда он будет начинать каждую работу четыре раза?
В целом, я чувствую, что должен быть лучший способ выполнения этих повторяющихся задач, но я не уверен, как это сделать. Есть ли у кого-нибудь интересное решение этой проблемы? Все советы приветствуются!
[ПРАВИТЬ] Я только что читал о Сельдерее с его расписанием. Хотя я действительно не понимаю, чем Сельдерей отличается от APScheduler и может ли он таким образом решить мои два вопроса, мне интересно, думает ли кто-нибудь, читающий это, что я должен больше исследовать Сельдерей?
[ЗАКЛЮЧЕНИЕ] Примерно два года спустя я читаю это, и я подумал, что мог бы сообщить вам, ребята, что у меня получилось. Я решил, что @BluePeppers был прав, говоря, что я не должен быть так тесно связан с экосистемой Колб. Поэтому я выбрал регулярные задания cron, выполняемые каждую минуту, которые задаются с помощью Ansible. Хотя это немного усложняет задачу (мне нужно было изучить Ansible и преобразовать некоторый код, чтобы его было достаточно запускать каждую минуту). Я думаю, что это более надежно. В настоящее время я использую удивительный pythonr-rq для постановки в очередь заданий синхронизации (проверка API и отправка электронной почты). Я только что узнал о rq-планировщике. Я еще не тестировал его, но, похоже, он делает именно то, что мне было нужно в первую очередь. Так что, возможно, это совет для будущих читателей этого вопроса.
В остальном я просто желаю всем вам прекрасного дня!
Ответ №1:
(1)
Вы можете использовать app.app_context()
контекстный менеджер для настройки контекста приложения. Я предполагаю, что использование будет выглядеть примерно так:
from apscheduler.scheduler import Scheduler
def checkSecondApi():
with app.app_context():
# Do whatever you were doing to check the second API
@app.before_first_request
def initialize():
apsched = Scheduler()
apsched.start()
apsched.add_interval_job(checkFirstAPI, seconds=5)
apsched.add_interval_job(checkSecondAPI, seconds=5)
apsched.add_interval_job(checkThirdAPI, seconds=5)
В качестве альтернативы вы можете использовать декоратора
def with_application_context(app):
def inner(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
with app.app_context():
return func(*args, **kwargs)
return wrapper
return inner
@with_application_context(app)
def checkFirstAPI():
# Check the first API as before
(2)
Да, это все равно будет работать. Единственное (существенное) различие заключается в том, что ваше приложение не будет напрямую взаимодействовать с миром; оно будет проходить через обратный прокси-сервер или что-то еще через fastcgi/uwsgi/что угодно. Единственная проблема заключается в том, что если у вас запущено несколько экземпляров приложения, то будет создано несколько планировщиков. Чтобы справиться с этим, я бы посоветовал вам перенести свои внутренние задачи из приложения Flask и использовать инструмент, предназначенный для регулярного выполнения задач (например, Сельдерей). Недостатком этого является то, что вы не сможете использовать такие вещи, как почта в колбе, но, имо, не слишком хорошо быть так тесно связанным с экосистемой колбы; что вы получаете, используя почту в колбе по сравнению со стандартной, не колбой, почтовой библиотекой?
Кроме того, разделение приложения значительно упрощает масштабирование отдельных компонентов по мере необходимости, по сравнению с наличием одного монолитного веб-приложения.
Комментарии:
1. Спасибо вам за ваш подробный ответ. И последнее: поскольку APScheduler работает отлично, как вы думаете, в чем будет преимущество использования сельдерея перед APScheduler? Что бы вы выбрали и почему?
2. Ну, Сельдерей предлагает вам гораздо больше, чем простое планирование. С учетом сказанного, я мало что знаю об APScheduler, и, читая документы сейчас, все выглядит совершенно нормально.
3. Я нахожу этот пост очень полезным. Но я хотел бы спросить, я использую базу данных SQL для своего приложения, которое из APScheduler или Сельдерея было бы более подходящим для использования? Я вижу редис в Сельдерее. Могу ли я вместо этого пойти на APScheduler?
4. Можете ли вы сказать мне, можно ли запустить запланированное задание только для одного процесса с помощью uwsgi ? когда у меня есть процессы 4 в моем файле uwsgi.ini, задачи выполняются с каждым процессом.
5. Спасибо за этот ответ, это очень помогает мне решить проблему, она работает как заклинание.