前言
作为 Django 应用程序开发人员,您经常遇到这样的情况:您希望能够执行周期性的异步后台任务。如果您想创建一些背景检查、发送通知或构建缓存,它会派上用场
我的第一选择是安装django-celery-beats。我对结果很满意。我能够根据用户配置动态配置我的周期性任务,因为 Celery 从数据库读取执行配置。
另一方面,我的应用程序现在依赖于celery(必须作为单独的服务运行)和Redis服务器(芹菜用作消息代理)。
应用程序的容器化变得很奇怪。我不确定,我是否应该将celery服务包含在容器内或作为使用docker-compose的依赖项。我还认为我只需要Redis实例来执行定期任务是荒谬的。我还想减小hypervisord配置的大小。
我想保持灵活性,但减少依赖项和配置样板的数量。
解决方案
我celery在不需要的应用程序中去掉了(我没有使用其他伟大的 celery 功能)。我只想从django.conf.settings或数据库加载周期性。
我使用Alpine Linux作为我的应用程序的基本映像。基本操作系统已经可以处理周期性任务的执行。这是好老crond。该配置在Alpine Linux docs 中有描述。
我创建了一个简单的Django管理命令叫setup我的应用程序。我们还假设我有另一个 Django 管理命令popularity,它应该每五分钟运行一次。在这个例子中,我将从 Django 设置变量中读取一个配置,CRON_JOBS它可能如下所示:
CRON_JOBS = {
'popularity': '*/5 * * * *'
}
变量由Django management command名称和 periodicity对组成。该命令将crond使用python-crontab库根据它创建一个配置。该命令应该在第一次运行之前和每次配置更改时运行(请记住,因为您已经从管理命令创建 CRON 作业规则,您可以使用 ORM 从数据库读取配置)。
# management/commands/setup.py
from crontab import CronTab
from django.core.management import BaseCommand
class Command(BaseCommand):
cron = CronTab(tabfile='/etc/crontabs/root', user=True)
cron.remove_all()
for command, schedule in settings.CRON_JOBS.items():
job = cron.new(command='cd /usr/src/app && python3 manage.py {}'.format(command), comment=command)
job.setall(schedule)
job.enable()
cron.write()
请记住,如果您从数据库加载数据,则必须使用setup管理命令再次执行此更改。您可以使用call_command方法实现此目的。
from Django.core import management
def save_config():
# do whatever you want
management.call_method('setup')
创建容器
正如我之前所说,我的 Django 应用程序基于 Alpine Linux 容器,并从entrypoint.sh负责(按上述顺序)执行:
1.执行migrations,
2.执行setup创建初始 CRON 作业配置的管理命令,
3.并初始化supervisord服务(将管理gunicorn和crond服务)。
supervisord 配置
我supervisord用来管理gunicorn应用服务器和crond服务的执行。
如果应用程序位于/usr/src/app目录中并gunicorn安装在目录中,则/root/.local/bin/gunicorn 可能supervisor.conf如下所示:
[supervisord]
nodaemon=true
[program:gunicorn]
directory=/usr/src/app
command=/root/.local/bin/gunicorn -b 0.0.0.0:8000 -w 4 my_app.wsgi --log-level=debug --log-file=/var/log/gunicorn.log
autostart=true
autorestart=true
priority=900
[program:cron]
directory=/usr/src/app
command=crond -f
autostart=true
autorestart=true
priority=500
stdout_logfile=/var/log/cron.std.log
stderr_logfile=/var/log/cron.err.log
Dockerfile
最小Dockerfile
必须至少包含:
- 复制应用程序源代码,
- 安装依赖项,
- 复制配置,
- 入口点的执行。
FROM alpine:3.15
WORKDIR /usr/src/app
# Copy source
COPY . .
# Dependencies
RUN apk add --no-cache python3 supervisor
RUN pip3 install --user gunicorn
RUN pip3 install --user -r requirements.txt
# Configuration
COPY conf/supervisor.conf /etc/supervisord.conf
# Execution
RUN chmod +x conf/entrypoint.sh
CMD ["conf/entrypoint.sh"]
发表评论 取消回复