Запуск фоновых задач Heroku только с 1 веб-динамо и 0 рабочими динамо
У меня есть приложение Python Flask на Heroku, которое обслуживает веб-страницы, но также позволяет запускать определенные задачи, которые, по моему мнению, лучше всего структурировать как фоновые. Таким образом, я следовал за Heroku rq
учебник по настройке фоновых задач. Мой Procfile выглядит так:
web: python app.py
worker: python worker.py
Тем не менее, мои процессы в настоящее время масштабируются web=1 worker=0
, Учитывая, что этот фоновый процесс не будет запускаться очень часто, для меня не имеет смысла выделять для него весь динамо, а затем платить 34 доллара в месяц за что-то такое маленькое.
Вопрос:
- Если я оставлю
worker
процесс объявлен в моем Procfile, но сохранить масштабирование вweb=1 worker=0
, будут ли мои процессы в очереди в конечном итоге выполняться на моем доступном веб-dyno? Или процессы в очереди никогда не запустятся? - Если процессы в очереди никогда не будут запущены, есть ли другой способ сделать это, например, с помощью
twisted
в моем веб-приложении для выполнения задач асинхронно?
Дополнительная информация
worker.py
выглядит так:
import os
import redis
from rq import Worker, Queue, Connection
listen = ['high', 'default', 'low']
redis_url = os.getenv('REDISTOGO_URL', 'redis://localhost:6379')
conn = redis.from_url(redis_url)
if __name__ == '__main__':
with Connection(conn):
worker = Worker(map(Queue, listen))
worker.work()
Логика в основном приложении, которое ставит в очередь процесс, выглядит следующим образом:
from rq import Queue
from worker import conn
q = Queue(connection=conn)
q.enqueue(myfunction, myargument)
4 ответа
$ cat Procfile
web: bin/web
$ cat bin/web
python app.py &
python worker.py
В настоящее время я использую и свой веб-и внутренний планировщик в Heroku, используя только 1 dyno.
Идея состоит в том, чтобы предоставить один основной скрипт на python для Heroku, который будет запущен в 1 дина. Этот скрипт используется для запуска процесса (ов) веб-сервера и процесса (ов) планировщика клиента. Затем вы можете определить свои задания и добавить их в пользовательский планировщик.
APScheduler используется в моем случае.
Вот что я сделал:
в Procfile:
web: python run_app.py #the main startup script
в run_app.py:
# All the required imports
from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor
from apscheduler.triggers.cron import CronTrigger
from run_housekeeping import run_housekeeping
from apscheduler.schedulers.background import BackgroundScheduler
import os
def run_web_script():
# start the gunicorn server with custom configuration
# You can also using app.run() if you want to use the flask built-in server -- be careful about the port
os.system('gunicorn -c gunicorn.conf.py web.jobboard:app --debug')
def start_scheduler():
# define a background schedule
# Attention: you cannot use a blocking scheduler here as that will block the script from proceeding.
scheduler = BackgroundScheduler()
# define your job trigger
hourse_keeping_trigger = CronTrigger(hour='12', minute='30')
# add your job
scheduler.add_job(func=run_housekeeping, trigger=hourse_keeping_trigger)
# start the scheduler
scheduler.start()
def run():
start_scheduler()
run_web_script()
if __name__ == '__main__':
run()
Я также использую 4 рабочих процесса для обслуживания сети от Gunicorn - который работает отлично.
В gunicorn.conf.py:
loglevel = 'info'
errorlog = '-'
accesslog = '-'
workers = 4
Вы можете проверить этот проект в качестве примера: Zjobs @ Github
Вы можете использовать менеджер процессов, например, God или Monit.
С богом, вы можете настроить свою конфигурацию так
God.watch do |w|
w.name = "app"
w.start = "python app.py"
w.keepalive
end
God.watch do |w|
w.name = "worker"
w.start = "python worker.py"
w.keepalive
end
Затем вы кладете это в свой Procfile
god -c path/to/config.god -D
По умолчанию он автоматически перезапускает процесс в случае сбоя, и вы можете настроить его на перезапуск приложения, если использование памяти становится слишком высоким. Ознакомьтесь с документацией.
Чтобы запустить и запустить процесс в фоновом режиме:
Procfile:
run: python my_app.py
А потом выполните:
heroku ps:scale run=1
Вы должны взглянуть на Heroku Scheduler, он позволит вам запускать определенную задачу с запланированным интервалом, например каждые 10 минут. Если у вас уже есть настройки рабочего, вы можете добавить:
heroku run worker