使用 python 包装器脚本在 upstart 中启动和停止 celery 进程

Starting and stopping celery processes in upstart with a python wrapper script

所以我们有一个有 celery worker 的应用程序。我们使用如下所示的 upstart 文件 /etc/init/fact-celery.conf 启动这些 worker:

description "FaCT Celery Worker."
start on runlevel [2345]
stop on runlevel [06]

respawn
respawn limit 10 5

setuid fact
setgid fact

script
  [ -r /etc/default/fact ] && . /etc/default/fact

  if [ "$START_CELERY" != "yes" ]; then
    echo "Service disabled in '/etc/default/fact'. Not starting."
    exit 1
  fi

  ARGUMENTS=""

  if [ "$BEAT_SERVICE" = "yes" ]; then
    ARGUMENTS="--beat"
  fi

  /usr/bin/fact celery worker --loglevel=INFO --events --schedule=/var/lib/fact/celerybeat-schedule --queues=$CELERY_QUEUES $ARGUMENTS
end script

它调用如下所示的 python 包装器脚本:

#!/bin/bash

WHOAMI=$(whoami)
PYTHONPATH=/usr/share/fact
PYTHON_BIN=/opt/fact-virtual-environment/bin/python
DJANGO_SETTINGS_MODULE=fact.settings.staging

if [ ${WHOAMI} != "fact" ];
then
  sudo -u fact [=12=] $*;
else
  # Python needs access to the CWD, but we need to deal with apparmor restrictions
  pushd $PYTHONPATH &> /dev/null
  PYTHONPATH=${PYTHONPATH} DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE}  ${PYTHON_BIN} -m fact.managecommand $*;
  popd &> /dev/null
fi

此设置的问题在于,当我们停止服务时,我们留下了没有死亡的 pact-celery worker。出于某种原因,暴发户无法跟踪分叉的进程。我在一些类似的帖子中读到,upstart 无法跟踪两个以上的分叉。

我试过使用 expect fork,但每当我尝试启动或停止服务时,upstart 就会挂起。

我在这篇文章中发现的其他帖子说直接调用 python 过程而不是使用包装脚本,但我们已经围绕这些脚本构建了 apparmor 配置文件,并且我们的工作流程中还有其他内容非常依赖他们。

有什么方法可以使用当前的包装器脚本来处理在服务停止时杀死所有 celery worker 的问题吗?

Workers Guide中对此有一些讨论,但基本上通常的过程是向worker发送一个TERM信号,这将导致它等待所有当前运行 退出清理前要完成的任务。

或者,如果您希望它立即停止并可能丢失数据,则可以发送 KILL 信号,但是正如您所说,芹菜无法拦截信号并清除 children 在这种情况下。提到的唯一办法是像这样手动清理 children:

$ ps auxww | grep 'celery worker' | awk '{print }' | xargs kill -9