跳转至

守护进程

如今大多数 Linux 发行版都使用 systemd 来管理系统和用户服务的生命周期。

您可以通过输入以下命令来检查您的 Linux 发行版是否使用 systemd:

systemctl --version
systemd 249 (v249.9-1.fc35)
+PAM +AUDIT +SELINUX -APPARMOR +IMA +SMACK +SECCOMP +GCRYPT +GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 +PWQUALITY +P11KIT +QRENCODE +BZIP2 +LZ4 +XZ +ZLIB +ZSTD +XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified

如果您有类似的输出,请参考 使用 systemd 获取指导。

然而,init.d 脚本在这些 Linux 发行版中仍然应该有效,因为 systemd 提供了 systemd-sysv 兼容层,它会自动从我们提供的 init.d 脚本生成服务。

如果您为多个 Linux 发行版打包 Celery,并且其中一些不支持 systemd,或者也面向其他 Unix 系统,您可能需要参考 通用初始化脚本

通用初始化脚本

请参阅 Celery 发行版中的 extra/generic-init.d/ 目录。

该目录包含用于 celery worker 程序的通用 bash 初始化脚本,这些脚本应该可以在 Linux、FreeBSD、OpenBSD 和其他类 Unix 平台上运行。

初始化脚本: celeryd

用法: /etc/init.d/celeryd {start|stop|restart|status}

配置文件: /etc/default/celeryd

要正确配置此脚本以运行 worker,您至少需要告诉它在启动时切换到哪个目录(以找到包含您的应用程序或配置模块的模块)。

守护进程脚本由文件 /etc/default/celeryd 配置。这是一个 shell (sh) 脚本,您可以在其中添加环境变量,如下面的配置选项所示。要添加影响 worker 的实际环境变量,您还必须导出它们(例如,export DISPLAY=":0"

需要超级用户权限

初始化脚本只能由 root 用户使用,并且 shell 配置文件也必须归 root 所有。

非特权用户不需要使用初始化脚本,而是可以使用 celery multi 实用程序(或 celery worker --detach):

celery -A proj multi start worker1 \
    --pidfile="$HOME/run/celery/%n.pid" \
    --logfile="$HOME/log/celery/%n%I.log"

celery -A proj multi restart worker1 \
    --logfile="$HOME/log/celery/%n%I.log" \
    --pidfile="$HOME/run/celery/%n.pid

celery multi stopwait worker1 --pidfile="$HOME/run/celery/%n.pid"

示例配置

这是一个 Python 项目的示例配置。

/etc/default/celeryd
# 要启动的节点名称
#   大多数人只会启动一个节点:
CELERYD_NODES="worker1"
#   但您也可以启动多个节点并在 CELERYD_OPTS 中为每个节点配置设置
#CELERYD_NODES="worker1 worker2 worker3"
#   或者,您可以指定要启动的节点数量:
#CELERYD_NODES=10

# 'celery' 命令的绝对或相对路径:
CELERY_BIN="/usr/local/bin/celery"
#CELERY_BIN="/virtualenvs/def/bin/celery"

# 要使用的应用程序实例
# 如果不使用应用程序,请注释掉此行
CELERY_APP="proj"
# 或完全限定:
#CELERY_APP="proj.tasks:app"

# 启动时要切换到的目录。
CELERYD_CHDIR="/opt/Myproject/"

# 传递给 worker 的额外命令行参数
CELERYD_OPTS="--time-limit=300 --concurrency=8"
# 通过将节点名称附加到参数来配置特定于节点的设置:
#CELERYD_OPTS="--time-limit=300 -c 8 -c:worker2 4 -c:worker3 2 -Ofair:worker1"

# 将日志级别设置为 DEBUG
#CELERYD_LOG_LEVEL="DEBUG"

# %n 将被替换为节点名称的第一部分。
CELERYD_LOG_FILE="/var/log/celery/%n%I.log"
CELERYD_PID_FILE="/var/run/celery/%n.pid"

# Worker 应该以非特权用户身份运行。
#   您需要手动创建此用户(或者您可以选择
#   已经存在的用户/组组合(例如,nobody))。
CELERYD_USER="celery"
CELERYD_GROUP="celery"

# 如果启用,将在缺失时创建 pid 和日志目录,
# 并由配置的用户 ID/组拥有。
CELERY_CREATE_DIRS=1

使用登录 shell

您可以通过使用登录 shell 来继承 CELERYD_USER 的环境:

CELERYD_SU_ARGS="-l"

请注意,这不被推荐,您应该只在绝对必要时使用此选项。

Django 示例配置

Django 用户现在使用与上面完全相同的模板,但请确保定义 Celery 应用程序实例的模块也为 DJANGO_SETTINGS_MODULE 设置了默认值,如 :ref:django-first-steps 中的示例 Django 项目所示。

可用选项

选项 描述
CELERY_APP 要使用的应用程序实例(celery --app 参数的值)。
CELERY_BIN celery 程序的绝对或相对路径。 示例: celery /usr/local/bin/celery /virtualenvs/proj/bin/celery /virtualenvs/proj/bin/python -m celery
CELERYD_NODES 要启动的节点名称列表(用空格分隔)。
CELERYD_OPTS worker 的额外命令行参数,请参阅 celery worker --help 获取列表。这也支持 multi 使用的扩展语法 来配置各个节点的设置。 请参阅 celery multi --help 获取一些多节点配置示例。
CELERYD_CHDIR 启动时要切换到的路径。默认是保持在当前目录。
CELERYD_PID_FILE PID 文件的完整路径。默认是 /var/run/celery/%n.pid
CELERYD_LOG_FILE worker 日志文件的完整路径。默认是 /var/log/celery/%n%I.log **注意**:在使用 prefork 池时,使用 %I 很重要,因为 多个进程共享同一个日志文件会导致竞争条件。
CELERYD_LOG_LEVEL worker 日志级别。默认是 INFO。
CELERYD_USER 运行 worker 的用户。默认是当前用户。
CELERYD_GROUP 运行 worker 的组。默认是当前用户。
CELERY_CREATE_DIRS 始终创建目录(日志目录和 pid 文件目录)。 默认仅在未设置自定义日志文件/pid 文件时创建目录。
CELERY_CREATE_RUNDIR 始终创建 pid 文件目录。默认仅在未设置自定义 pid 文件位置时启用。
CELERY_CREATE_LOGDIR 始终创建日志文件目录。默认仅在未设置自定义日志文件位置时启用。

初始化脚本: celerybeat

用法: /etc/init.d/celerybeat {start|stop|restart}

配置文件: /etc/default/celerybeat/etc/default/celeryd

示例配置

这是一个 Python 项目的示例配置:

/etc/default/celerybeat
# 'celery' 命令的绝对或相对路径:
CELERY_BIN="/usr/local/bin/celery"
#CELERY_BIN="/virtualenvs/def/bin/celery"

# 要使用的应用程序实例
# 如果不使用应用程序,请注释掉此行
CELERY_APP="proj"
# 或完全限定:
#CELERY_APP="proj.tasks:app"

# 启动时要切换到的目录。
CELERYBEAT_CHDIR="/opt/Myproject/"

# 传递给 celerybeat 的额外参数
CELERYBEAT_OPTS="--schedule=/var/run/celery/celerybeat-schedule"

Django 示例配置

您应该使用与上面相同的模板,但请确保 DJANGO_SETTINGS_MODULE 变量已设置(并导出),并且 CELERYD_CHDIR 设置为项目目录:

export DJANGO_SETTINGS_MODULE="settings"

CELERYD_CHDIR="/opt/MyProject"

可用选项

选项 描述
CELERY_APP 要使用的应用程序实例(celery --app 参数的值)。
CELERYBEAT_OPTS 传递给 celery beat 的额外参数,请参阅 celery beat --help 获取可用选项列表。
CELERYBEAT_PID_FILE PID 文件的完整路径。默认是 /var/run/celeryd.pid
CELERYBEAT_LOG_FILE 日志文件的完整路径。默认是 /var/log/celeryd.log
CELERYBEAT_LOG_LEVEL 要使用的日志级别。默认是 INFO
CELERYBEAT_USER 运行 beat 的用户。默认是当前用户。
CELERYBEAT_GROUP 运行 beat 的组。默认是当前用户。
CELERY_CREATE_DIRS 始终创建目录(日志目录和 pid 文件目录)。默认仅在未设置自定义日志文件/pid 文件时创建目录。
CELERY_CREATE_RUNDIR 始终创建 pid 文件目录。默认仅在未设置自定义 pid 文件位置时启用。
CELERY_CREATE_LOGDIR 始终创建日志文件目录。默认仅在未设置自定义日志文件位置时启用。

故障排除

如果无法使初始化脚本正常工作,您应该尝试在详细模式下运行它们:

sh -x /etc/init.d/celeryd start

这可以揭示服务无法启动的原因。

如果 worker 以 "OK" 启动但几乎立即退出,并且日志文件中没有证据,那么可能存在错误,但由于守护进程的标准输出已经关闭,您将无法在任何地方看到它们。对于这种情况,您可以使用 C_FAKEFORK 环境变量跳过守护进程步骤:

C_FAKEFORK=1 sh -x /etc/init.d/celeryd start

现在您应该能够看到错误了。

通常,此类错误是由文件读写权限不足、配置模块、用户模块、第三方库中的语法错误,甚至 Celery 本身引起的。

使用 systemd

用法: systemctl {start|stop|restart|status} celery.service

配置文件: /etc/conf.d/celery

服务文件: celery.service

这是一个示例的systemd文件:

/etc/systemd/system/celery.service
[Unit]
Description=Celery Service
After=network.target

[Service]
Type=forking
User=celery
Group=celery
EnvironmentFile=/etc/conf.d/celery
WorkingDirectory=/opt/celery
ExecStart=/bin/sh -c '${CELERY_BIN} -A $CELERY_APP multi start $CELERYD_NODES \
    --pidfile=${CELERYD_PID_FILE} --logfile=${CELERYD_LOG_FILE} \
    --loglevel="${CELERYD_LOG_LEVEL}" $CELERYD_OPTS'
ExecStop=/bin/sh -c '${CELERY_BIN} multi stopwait $CELERYD_NODES \
    --pidfile=${CELERYD_PID_FILE} --logfile=${CELERYD_LOG_FILE} \
    --loglevel="${CELERYD_LOG_LEVEL}"'
ExecReload=/bin/sh -c '${CELERY_BIN} -A $CELERY_APP multi restart $CELERYD_NODES \
    --pidfile=${CELERYD_PID_FILE} --logfile=${CELERYD_LOG_FILE} \
    --loglevel="${CELERYD_LOG_LEVEL}" $CELERYD_OPTS'
Restart=always

[Install]
WantedBy=multi-user.target

一旦你将该文件放入 /etc/systemd/system,你应该运行 systemctl daemon-reload 以便Systemd识别该文件。每次修改该文件时,你也应该运行该命令。如果你希望 celery 服务在系统(重新)启动时自动启动,请使用 systemctl enable celery.service

可选地,你可以为celery服务指定额外的依赖项:例如,如果你使用 RabbitMQ 作为代理,你可以在 [Unit] systemd部分 中的 After=Requires= 中指定 rabbitmq-server.service

要配置用户、组、chdir 更改设置:在 /etc/systemd/system/celery.service 中定义的 UserGroupWorkingDirectory

你也可以使用 systemd-tmpfiles 来创建工作目录(用于日志和 pid 文件)。

/etc/tmpfiles.d/celery.conf
d /run/celery 0755 celery celery -
d /var/log/celery 0755 celery celery -

示例配置

这是一个Python项目的示例配置:

/etc/conf.d/celery
# 要启动的节点名称
# 这里我们有一个单节点
CELERYD_NODES="w1"
# 或者我们可以有三个节点:
#CELERYD_NODES="w1 w2 w3"

# 'celery'命令的绝对或相对路径:
CELERY_BIN="/usr/local/bin/celery"
#CELERY_BIN="/virtualenvs/def/bin/celery"

# 要使用的应用实例
# 如果不使用应用,请注释掉这一行
CELERY_APP="proj"
# 或者完全限定:
#CELERY_APP="proj.tasks:app"

# 如何调用manage.py
CELERYD_MULTI="multi"

# 工作进程的额外命令行参数
CELERYD_OPTS="--time-limit=300 --concurrency=8"

# - %n 将被节点名称的第一部分替换。
# - %I 将被当前子进程索引替换
#   在使用prefork池时很重要,以避免竞争条件。
CELERYD_PID_FILE="/var/run/celery/%n.pid"
CELERYD_LOG_FILE="/var/log/celery/%n%I.log"
CELERYD_LOG_LEVEL="INFO"

# 你可能希望为Celery Beat添加这些选项
CELERYBEAT_PID_FILE="/var/run/celery/beat.pid"
CELERYBEAT_LOG_FILE="/var/log/celery/beat.log"

服务文件: celerybeat.service

这是一个Celery Beat的示例systemd文件:

/etc/systemd/system/celerybeat.service
[Unit]
Description=Celery Beat Service
After=network.target

[Service]
Type=simple
User=celery
Group=celery
EnvironmentFile=/etc/conf.d/celery
WorkingDirectory=/opt/celery
ExecStart=/bin/sh -c '${CELERY_BIN} -A ${CELERY_APP} beat  \
    --pidfile=${CELERYBEAT_PID_FILE} \
    --logfile=${CELERYBEAT_LOG_FILE} --loglevel=${CELERYD_LOG_LEVEL}'
Restart=always

[Install]
WantedBy=multi-user.target

一旦你将该文件放入 /etc/systemd/system,你应该运行 systemctl daemon-reload 以便 Systemd 识别该文件。每次修改该文件时,你也应该运行该命令。如果你希望 celery beat 服务在系统(重新)启动时自动启动,请使用 systemctl enable celerybeat.service

使用超级用户权限(root)运行工作进程

使用超级用户权限运行工作进程是一种非常危险的做法。应该总是有避免以 root 身份运行的解决方案。Celery 可能会在通过 pickle 序列化的消息中运行任意代码 - 这是危险的,尤其是在以 root 身份运行时。

默认情况下,Celery不会以root身份运行工作进程。相关的错误消息可能不会在日志中可见,但如果使用了 C_FAKEFORK 则可能会看到。

要强制 Celery 以 root 身份运行工作进程,请使用 C_FORCE_ROOT

当以 root 身份运行但没有 C_FORCE_ROOT 时,工作进程将显示以 "OK" 启动,但随后立即退出且无明显错误。这个问题可能会在新的开发或生产环境中(无意中)以root身份运行项目时出现。