如何在Heroku的Django中安排一次性事件?

时间:2016-04-14 23:25:17

标签: python django heroku

我对计划将来在Heroku的分布式环境中触发一次事件所需的软件设计有疑问。

我认为写下我想要达到的目标会更好,但我确实完成了我的研究,即使经过两个小时的工作也无法自己解决。

让我们说views.py我有一个功能:

def after_6_hours():
    print('6 hours passed.')


def create_game():
    print('Game created')
    # of course time will be error, but that's just an example
    scheduler.do(after_6_hours, time=now + 6)

所以我想要实现的是能够在after_6_hours被调用后6小时正好运行create_game函数。现在,正如您所看到的,此函数是由通常的clock.pytask.py或其他等文件定义的。

现在,如何让我的整个应用程序始终在Heroku中运行,并且能够将此作业添加到此虚构的队列 - scheduler库中?

另外,我不能使用Heroku的Temporizer附加组件。 APScheduler和Python rq的组合看起来很有希望,但是示例很简单,都安排在clock.py内的同一个文件中,而我只是不知道如何将所有内容与我的设置结合在一起。提前谢谢!

1 个答案:

答案 0 :(得分:3)

在Heroku中,您可以让您的Django应用程序在Web Dyno中运行,该应用程序将负责为您的应用程序提供服务并安排任务。 例如(请注意,我没有测试运行代码):

创建after_hours.py,它将具有您要安排的功能(请注意,我们将在worker中使用相同的源代码)。

def after_6_hours():
        print('6 hours passed.')
使用rqviews.py

(请注意rq仅在您的情况下不足以安排任务)和rq-scheduler

from redis import Redis
from rq_scheduler import Scheduler
from datetime import timedelta

from after_hours import after_6_hours

def create_game():
    print('Game created')

    scheduler = Scheduler(connection=Redis()) # Get a scheduler for the "default" queue
    scheduler.enqueue_in(timedelta(hours=6), after_6_hours) #schedules the job to run 6 hours later.

调用create_game()应安排after_6_hours()在6小时后运行。
提示:您可以使用Redis To Go附加组件在Heroku中设置Redis

下一步是运行rqscheduler工具,该工具每分钟轮询一次Redis以查看当时是否有任何要执行的作业并将其放入队列(rq工作人员将成为听)。

现在,在Worker Dyno中创建一个文件after_hours.py

def after_6_hours():
    print('6 hours passed.')
    #Better return something

并创建另一个文件worker.py

import os

import redis
from rq import Worker, Queue, Connection

from after_hours import after_6_hours

listen = ['high', 'default', 'low'] # while scheduling the task in views.py we sent it to default

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()

并运行此worker.py

python worker.py

这应该在Worker Dyno中运行计划任务(在这种情况下为afer_6_hours)。 请注意,此处的关键是为工作人员提供相同的源代码(在这种情况下为after_hours.py)。 rq docs

强调了相同的内容
  

确保工作者和工作生成器完全共享   相同的源代码。

如果有帮助,docs中有一个提示来处理不同的代码库。

  

对于Web进程无权访问源代码的情况   在worker中运行(即代码库X调用延迟函数   从代码库Y),您可以将函数作为字符串引用传递,   太

 q = Queue('low', connection=redis_conn)
 q.enqueue('my_package.my_module.my_func', 3, 4)

希望rq-scheduler也尊重这种传递字符串而不是函数对象的方式。

只要您理解这一点,就可以使用任何模块/日程安排工具(Celery / RabbitMQ,APScheduler等)。