Django在Elastic Beanstalk上的定期任务(可能是芹菜节拍)

Jon*_*rds 8 django amazon-web-services celery celerybeat amazon-elastic-beanstalk

我正在尝试在Elastic Beanstalk上为我的Django应用程序设置日常任务.似乎没有一种可接受的方式来设置它,因为芹菜节拍是Django中定期任务的首选解决方案,但对于负载平衡环境并不是很好.

我已经看到一些解决方案,比如使用leader_only = True设置芹菜节拍,只运行一个实例,但这会留下单点故障.我已经看到其他解决方案允许芹菜的许多实例击败并使用锁来确保只有一个任务通过,但除非失败的实例重新启动,否则最终还是不会完全失败?我看到的另一个建议是有一个单独的实例来运行芹菜节拍,但这仍然是一个问题,除非它有一些方法重新启动它失败.

这个问题有没有合适的解决方案?我宁愿不必照看调度程序,因为很容易注意到我的任务直到一段时间才运行.

std*_*ave 0

我建议制作一个与 cron 一起运行的管理命令

使用此方法,您可以使用完整的 Django ORM、所有方法等。将脚本包装在 try/ except 中,您可以选择以任何您希望的方式记录失败 - 电子邮件通知、外部日志系统(如 Sentry)、直接记录到数据库等。

我使用supervisord 来运行cron,效果很好。它依赖于经过时间考验的工具,不会让您失望。

最后,使用数据库单例来跟踪批处理作业是否已运行或当前正在运行负载平衡的多个 Django 实例的环境中并不是一个坏习惯,即使您对此感到有点讨厌。DB 是告诉您 DB 是否正在处理的非常可靠的方法。

cron 的一件烦人的事情是它不导入 Django 可能需要的环境变量。我用一个简单的 Python 脚本解决了这个问题。

它在启动时写入 crontab,其中包含所需的环境变量等。此示例适用于 EBS 上的 Ubuntu,但应该具有相关性。

#!/usr/bin/env python

# run-cron.py
# sets environment variable crontab fragments and runs cron

import os
from subprocess import call
from master.settings import IS_AWS

# read django's needed environment variables and set them in the appropriate crontab fragment
eRDS_HOSTNAME = os.environ["RDS_HOSTNAME"]
eRDS_DB_NAME = os.environ["RDS_DB_NAME"]
eRDS_PASSWORD = os.environ["RDS_PASSWORD"]
eRDS_USERNAME = os.environ["RDS_USERNAME"]

try:
    eAWS_STAGING = os.environ["AWS_STAGING"]
except KeyError:
    eAWS_STAGING = None

try:
    eAWS_PRODUCTION = os.environ["AWS_PRODUCTION"]
except KeyError:
    eAWS_PRODUCTION = None

eRDS_PORT = os.environ["RDS_PORT"]

if IS_AWS:
    fto = '/etc/cron.d/stortrac-cron'
else:
    fto = 'test_cron_file'

with open(fto,'w+') as file:
    file.write('# Auto-generated cron tab that imports needed variables and runs a python script')

    file.write('\nRDS_HOSTNAME=')
    file.write(eRDS_HOSTNAME)
    file.write('\nRDS_DB_NAME=')
    file.write(eRDS_DB_NAME)
    file.write('\nRDS_PASSWORD=')
    file.write(eRDS_PASSWORD)
    file.write('\nRDS_USERNAME=')
    file.write(eRDS_USERNAME)
    file.write('\nRDS_PORT=')
    file.write(eRDS_PORT)
    if eAWS_STAGING is not None:
        file.write('\nAWS_STAGING=')
        file.write(eAWS_STAGING)
    if eAWS_PRODUCTION is not None:
        file.write('\nAWS_PRODUCTION=')
        file.write(eAWS_PRODUCTION)

    file.write('\n')

    # Process queue of gobs
    file.write('\n*/8 * * * * root python /code/app/manage.py queue --process-queue')
    # Every 5 minutes, double-check thing is done
    file.write('\n*/5 * * * * root python /code/app/manage.py thing --done')
    # Every 4 hours, do this
    file.write('\n8 */4 * * * root python /code/app/manage.py process_this')
    # etc.
    file.write('\n3 */4 * * * root python /ode/app/manage.py etc --silent')
    file.write('\n\n')

if IS_AWS:
    args = ["cron","-f"]
    call(args)
Run Code Online (Sandbox Code Playgroud)

在supervisord.conf中:

[program:cron]
command = python /my/directory/runcron.py
autostart = true
autorestart = false
Run Code Online (Sandbox Code Playgroud)