Django 和 Celery - 更改后将代码重新加载到 Celery

Django and Celery - re-loading code into Celery after a change

如果我在 celery 为 运行 时更改 tasks.py,是否有一种机制可以重新加载更新后的代码?还是我必须关闭 Celery 重新加载?

我读到芹菜在旧版本中有一个 --autoreload 参数,但我在当前版本中找不到它:

celery: error: unrecognized arguments: --autoreload

您可以在父工作进程上尝试 SIGHUP,它会重新启动工作进程,但我不确定它是否会接收新任务。值得一试,认为 :)

不幸的是 --autoreload 不起作用,它是 deprecated

您可以使用提供 watchmedo shell 实用程序的 Watchdog 来根据文件事件执行操作。

pip install watchdog

您可以使用

启动 worker
watchmedo auto-restart -- celery worker -l info -A foo

默认情况下,它将监视当前目录中的所有文件。这些可以通过传递相应的参数来改变。

watchmedo auto-restart -d . -p '*.py' -- celery worker -l info -A foo

添加 -R 选项以递归查看文件。

如果您使用的是 django 并且不想依赖看门狗,可以使用一个简单的技巧来实现。 Django 有自动重载实用程序,运行服务器使用它在代码更改时重新启动 WSGI 服务器。

可以使用相同的功能重新加载芹菜工人。创建一个名为 celery 的单独管理命令。编写一个函数来杀死现有的 worker 并启动一个新的 worker。现在将此函数挂接到 autoreload,如下所示。对于 Django >= 2.2

import sys

import shlex
import subprocess
from django.core.management.base import BaseCommand
from django.utils import autoreload


class Command(BaseCommand):
    def handle(self, *args, **options):
        autoreload.run_with_reloader(self._restart_celery)

    @classmethod
    def _restart_celery(cls):
        if sys.platform == "win32":
            cls.run('taskkill /f /t /im celery.exe')
            cls.run('celery -A phoenix worker --loglevel=info --pool=solo')
        else:  # probably ok for linux2, cygwin and darwin. Not sure about os2, os2emx, riscos and atheos
            cls.run('pkill celery')
            cls.run('celery worker -l info -A foo')

    @staticmethod
    def run(cmd):
        subprocess.call(shlex.split(cmd))

对于 django < 2.2

import sys

import shlex
import subprocess
from django.core.management.base import BaseCommand
from django.utils import autoreload


class Command(BaseCommand):
    def handle(self, *args, **options):
        autoreload.main(self._restart_celery)

    @classmethod
    def _restart_celery(cls):
        if sys.platform == "win32":
            cls.run('taskkill /f /t /im celery.exe')
            cls.run('celery -A phoenix worker --loglevel=info --pool=solo')
        else:  # probably ok for linux2, cygwin and darwin. Not sure about os2, os2emx, riscos and atheos
            cls.run('pkill celery')
            cls.run('celery worker -l info -A foo')

    @staticmethod
    def run(cmd):
        subprocess.call(shlex.split(cmd))

现在您可以 运行 使用 python manage.py celery 的 celery worker,它会在代码库更改时自动重新加载。

这仅用于开发目的,请勿在生产中使用。

仅供参考,对于使用 Docker 的任何人,我找不到使上述选项起作用的简单方法,但我发现(与其他人一起)另一个确实使用的小脚本 here看门狗,工作完美。

在你的主目录下保存为some_name.py文件,添加pip install psutil和watchdog到requirements.txt,更新顶部的path/cmdline变量,然后在worker容器中你的 docker-compose.yml 插入:

command: python ./some_name.py

Watchmedog 在 docker 容器中对我不起作用。

这是我使用 Django 的方式:

# worker_dev.py (put it next to manage.py)
from django.utils import autoreload


def run_celery():
    from projectname import celery_app

    celery_app.worker_main(["-Aprojectname", "-linfo", "-Psolo"])


print("Starting celery worker with autoreload...")
autoreload.run_with_reloader(run_celery)

然后 运行 python worker_dev.py 或将其设置为您的 Dockerfile CMD 或 docker-compose command.