Python 仅使用1个web dyno和0个worker dyno运行Heroku后台任务
我在Heroku上有一个PythonFlask应用程序,它提供网页服务,但也允许启动某些任务,我认为这些任务最好作为后台任务。因此,我已经遵循了设置后台任务的步骤。我的proc文件如下所示:Python 仅使用1个web dyno和0个worker dyno运行Heroku后台任务,python,heroku,redis,Python,Heroku,Redis,我在Heroku上有一个PythonFlask应用程序,它提供网页服务,但也允许启动某些任务,我认为这些任务最好作为后台任务。因此,我已经遵循了设置后台任务的步骤。我的proc文件如下所示: web: python app.py worker: python worker.py import os import redis from rq import Worker, Queue, Connection listen = ['high', 'default', 'low'] redis_u
web: python app.py
worker: python 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)
web: bin/web
#!/bin/bash
python app.py &
python worker.py
但是,我的流程目前正在扩展web=1 worker=0
。考虑到这个后台流程不会经常运行,我觉得为它提供一个完整的dyno,然后为这么小的东西每月支付34美元是不明智的
问题:
- 如果我保留Procfile中声明的
进程,但将缩放保持在worker
,那么我的排队进程最终是否会在可用的web dyno上运行?或者排队的进程永远不会运行web=1 worker=0
- 如果排队的进程永远不会运行,有没有其他方法可以做到这一点,例如,在我的web应用程序中使用
异步运行任务twisted
worker.py
如下所示:
web: python app.py
worker: python 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)
web: bin/web
#!/bin/bash
python app.py &
python worker.py
让进程排队的主应用程序中的逻辑如下所示:
web: python app.py
worker: python 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)
web: bin/web
#!/bin/bash
python app.py &
python worker.py
修改
Procfile
如下所示:
web: python app.py
worker: python 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)
web: bin/web
#!/bin/bash
python app.py &
python worker.py
现在创建bin
目录,并创建文件bin/web
,如下所示:
web: python app.py
worker: python 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)
web: bin/web
#!/bin/bash
python app.py &
python worker.py
确保为此文件授予可执行权限:
$ chmod +x bin/web
您应该查看一下它,它将允许您按计划的时间间隔(例如每10分钟)运行特定的任务。如果您已经安装了worker,则可以添加:
heroku run worker
您可以使用诸如或之类的流程管理器 有了上帝,你可以像这样设置你的配置
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
然后你把这个放进你的文件里
god -c path/to/config.god -D
默认情况下,如果进程崩溃,它会自动重新启动进程,您可以将其配置为在内存使用率过高时重新启动应用程序。查看文档。我目前正在Heroku中运行我的web和后端调度程序,只使用1个dyno 这个想法是为Heroku提供一个主python脚本,让它在1 dyno中启动。此脚本用于启动web服务器进程和客户计划程序进程。 然后可以定义作业并将其添加到自定义计划程序 在我的案例中使用 这就是我所做的: 在proc文件中:
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()
我还使用Gunicorn提供的4个工作进程为web提供服务,运行非常好
在gunicorn.conf.py中:
loglevel = 'info'
errorlog = '-'
accesslog = '-'
workers = 4
您可能希望签出此项目,例如:要在后台启动并运行进程,请执行以下操作: 程序文件:
web: python run_app.py #the main startup script
run: python my_app.py
然后,执行:
heroku ps:scale run=1
我不知道heroku到底是如何工作的,但你能不能生成一个工作线程?您可以使用队列将作业推送到它…@korylprince是的,我可以这样做——这就是我异步将其写入代码的意思。不过,如果可能的话,我更愿意使用队列。我想我理解你的意思,但如果你能进一步解释你的答案,对我和社区都会更有帮助。基本上,他所做的是首先在后台运行应用程序,然后在前台运行worker。>“这是一个好做法吗?”好的做法是有多个二元体——这是heroku的意思。但有一个目的——为什么不呢?答案来自Heroku的python家伙。答案很好,但更多的解释会更好。我已经搜索了几个小时,我想我理解这个答案,但我无法找到适合我需要的解决方案。如何使用RubyonRails在同一个dyno上实现web站点和后台进程?我知道我可以做到这一点,但使用Heroku调度程序与使用后台队列并不完全相同。这是一个cron作业,10分钟的等待时间对于我只想推到后台以不延迟页面加载的任务来说可能太长了。另一个选择是使用heroku API并以分离模式运行进程。通过需要一个完整的队列,您需要一个正在运行的进程,或者让它在同一个Dyno中运行。如果您使用heroku API并在分离模式下发出heroku run命令,它的行为几乎就像队列一样。同意,我设想它在同一个dyno中运行。我认为这在heroku上没有意义。