【问题标题】:Running Heroku background tasks with only 1 web dyno and 0 worker dynos仅使用 1 个 web dyno 和 0 个 worker dyno 运行 Heroku 后台任务
【发布时间】:2023-03-07 18:49:01
【问题描述】:

我在 Heroku 上有一个 Python Flask 应用程序,它提供网页服务,但也允许启动某些任务,我认为这些任务最好构造为后台任务。因此,我按照Heroku rq tutorial 设置后台任务。我的 Procfile 看起来像这样:

web: python app.py
worker: python worker.py

但是,我的流程目前正在扩展web=1 worker=0。鉴于此后台进程不会经常运行,因此为它提供整个测功机然后为那么小的东西每月支付 34 美元对我来说似乎是不明智的。

问题:

  • 如果我保留在我的 Procfile 中声明的 worker 进程但将缩放保持在 web=1 worker=0,我的排队进程最终会在我可用的 web dyno 上运行吗?或者排队的进程永远不会运行?
  • 如果排队的进程永远不会运行,是否有其他方法可以做到这一点,例如,在我的 Web 应用程序中使用 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)

【问题讨论】:

  • 我不知道 heroku 是如何工作的,但你不能只产生一个工作线程吗?您可以使用 Queue 将作业推送给它...
  • @korylprince 是的,我可以这样做——这就是我将它异步写入代码的意思。不过,如果可能的话,我更喜欢排队。

标签: python heroku redis


【解决方案1】:

Procfile 修改为如下所示:

web: bin/web

现在创建bin 目录,并创建文件bin/web,如下所示:

#!/bin/bash
python app.py &
python worker.py

确保你给这个文件可执行权限:

$ chmod +x bin/web

【讨论】:

  • 我想我明白你的意思,但如果你能进一步解释你的答案,对我和社区都会更有帮助。
  • 他所做的基本上是先在后台运行应用程序,然后在前台运行worker。
  • > “这是一个好习惯吗?”好的做法是拥有多个测功机-这就是heroku。但对于一个测功机目的 - 为什么不呢。
  • 答案来自 Heroku 的 python 人。答案工作正常,但更多解释会很好。
  • 我一直在寻找几个小时,我想我理解这个答案,但我无法找到适合我需要的解决方案。我如何使用 ruby​​ on rails 在同一个测功机上实现网站和后台进程?
【解决方案2】:

您应该查看Heroku Scheduler,它将允许您以预定的时间间隔(例如每 10 分钟)运行特定任务。如果你已经有了你的工人设置,你可以添加:

heroku run worker

【讨论】:

  • 我知道我可以做到这一点,但使用 Heroku 调度程序与拥有后台队列并不完全相同。这是一项 cron 工作,对于我只想推送到后台以免延迟页面加载的任务而言,10 分钟的等待可能太长了。
  • 另一种选择是我们使用 heroku API 并以分离模式运行进程。通过需要一个完整的队列,您要么需要一个正在运行的进程,要么让它在同一个 Dyno 中运行。如果您使用 heroku API 并在分离模式下发出 heroku run 命令,它几乎就像一个队列一样。
  • 同意,我设想它在同一个测功机中运行。
【解决方案3】:

您可以使用流程管理器,例如 godmonit

有了上帝,你可以像这样设置你的配置

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

默认情况下,如果进程崩溃,它会自动重新启动进程,您可以将其配置为在内存使用率过高时重新启动应用程序。查看文档。

【讨论】:

  • 我认为这在 heroku 上没有意义。
【解决方案4】:

我目前仅使用 1 个测功机在 Heroku 中运行我的 Web 和后端调度程序。

想法是为 Heroku 提供一个主要的 python 脚本以在 1 dyno 中启动。此脚本用于启动 Web 服务器进程和客户调度程序进程。 然后,您可以定义您的作业并将它们添加到自定义调度程序。

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 个 Worker 进程从 Gunicorn 为网络提供服务——运行得非常好。

在 gunicorn.conf.py 中:

loglevel = 'info'
errorlog = '-'
accesslog = '-'
workers = 4

您可能想以这个项目为例:Zjobs@Github

【讨论】:

    【解决方案5】:

    在后台启动和运行进程:

    过程文件:

    run: python my_app.py
    

    然后,执行:

    heroku ps:scale run=1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-24
      • 2011-12-18
      • 1970-01-01
      • 2014-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-28
      相关资源
      最近更新 更多