如何在Heroku中的Django中安排一次活动?

Sam*_*ini 5 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)
Run Code Online (Sandbox Code Playgroud)

所以我想要实现的是能够在调用after_6_hours后的6小时内准确运行函数create_game。现在,你可以看到,这个功能是平常的定义出clock.pytask.py或等等等等文件。

现在,如何使我的整个应用程序始终在Heroku中运行,并能够将这项工作添加到这个虚构的现在scheduler库的队列中?

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

Lea*_*ner 3

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

Create after_hours.py,它将具有您要安排的功能(请注意,我们也将在工作程序中使用相同的源代码)。

def after_6_hours():
        print('6 hours passed.')
Run Code Online (Sandbox Code Playgroud)

在您的views.py使用中rq(请注意,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.
Run Code Online (Sandbox Code Playgroud)

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

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

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

def after_6_hours():
    print('6 hours passed.')
    #Better return something
Run Code Online (Sandbox Code Playgroud)

并创建另一个文件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()
Run Code Online (Sandbox Code Playgroud)

并运行这个worker.py

python worker.py
Run Code Online (Sandbox Code Playgroud)

这应该在 Worker Dyno 中运行计划任务(afer_6_hours在本例中)。请注意,这里的关键是让after_hours.py工作人员也可以使用相同的源代码(在本例中)。文档中强调了同样的内容rq

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

如果有帮助,文档中有处理不同代码库的提示。

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

 q = Queue('low', connection=redis_conn)
 q.enqueue('my_package.my_module.my_func', 3, 4)
Run Code Online (Sandbox Code Playgroud)

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

只要你了解这个东西,你就可以使用任何模块/调度工具(Celery/RabbitMQ、APScheduler 等)。