Как запустить собственные процессы демона с Django? - PullRequest
12 голосов
/ 16 ноября 2011

В моем проекте Django мне приходится многократно выполнять некоторую обработку в фоновом режиме. Эта обработка требует доступа к материалам Django, поэтому я включил его в команды Django и запустил как cronjob. Прямо сейчас я понимаю, что некоторые из них мне приходится делать чаще (у cronjob есть ограничение на запуск команды не чаще, чем раз в 1 минуту). Другая проблема заключается в том, что у меня недостаточно контроля, чтобы защитить выполнение одной и той же команды за один раз. Это происходит, когда одна обработка занимает больше одной минуты. Я думаю, что я должен управлять ими как демоны, но я ищу чистый способ сделать это с Джанго. Вы когда-нибудь сталкивались с этой проблемой или знаете какое-нибудь чистое решение для нее?

Ответы [ 4 ]

13 голосов
/ 16 ноября 2011

Мы выполняем много фоновой обработки для django, используя Celery http://celeryproject.org/. Это требует определенных усилий для настройки и есть некоторая кривая обучения, но как только она запущена и работает, это просто потрясающе.

3 голосов
/ 17 ноября 2011

Мы выбрали более простой подход - написать скрипт как обычный скрипт с бесконечным циклом, который выполняет итерацию по набору запросов, а затем использовать supervise, чтобы управлять им как демоном.По сути, это все, что нужно для запуска демона: -

$ sudo apt-get install daemontools daemontools-run
$ mkdir /etc/service/sendmsevad
$ echo -> /etc/service/sendmsevad/run
#!/bin/bash
exec /usr/local/bin/sendmsgd
$ sudo svc -d  /etc/service/sendmsgd
$ sudo svc -u  /etc/service/sendmsgd
$ sudo svstat /etc/service/sendmsgd
/etc/service/sendmsg: up (pid 10521) 479 seconds

Подробнее об этом - Как мне демонизировать произвольный скрипт в unix?

Теперь,/usr/local/bin/sendmsgd может выглядеть так: -

def main(args=None):
    while True:
        process_messages()
        time.sleep(10)

if __name__ == '__main__':
    import signal
    def signal_handler(signal, frame):
        sys.exit(0)
    signal.signal(signal.SIGINT, signal_handler)

    main(sys.argv)
2 голосов
/ 27 мая 2013

У меня возникли проблемы с пониманием документации на сайте Celery. Я нашел этот сайт . Который сделал хорошую работу, объясняя вещи. У меня все работает на системе Centos 6.2 с django-1.5 + Celery-3.0.17 + sqlite3. Единственной проблемой, с которой я столкнулся, была ошибка при поиске модуля настроек, я должен изменить его на «myprojectname.settings».

Шаг 1. Сделайте следующий скрипт в / etc / default / celeryd. Обратите внимание, что вам нужно будет изменить некоторые из содержимого в зависимости от вашей системы.

# Name of nodes to start, here we have a single node
CELERYD_NODES="w1"

# Where to chdir at start.
CELERYD_CHDIR="/var/www/some_folder/Myproject/"

# Python interpreter from environment, if using virtualenv
ENV_PYTHON="/somewhere/.virtualenvs/MyProject/bin/python"

# How to call "manage.py celeryd_multi"
CELERYD_MULTI="$ENV_PYTHON $CELERYD_CHDIR/manage.py celeryd_multi"

# How to call "manage.py celeryctl"
CELERYCTL="$ENV_PYTHON $CELERYD_CHDIR/manage.py celeryctl"

# Extra arguments to celeryd
CELERYD_OPTS="--time-limit=300 --concurrency=8"

# Name of the celery config module, don't change this.
CELERY_CONFIG_MODULE="celeryconfig"

# %n will be replaced with the nodename.
CELERYD_LOG_FILE="/var/log/celery/%n.log"
CELERYD_PID_FILE="/var/run/celery/%n.pid"

# Workers should run as an unprivileged user.
CELERYD_USER="celery"
CELERYD_GROUP="celery"

# Set any other env vars here too!
PROJET_ENV="PRODUCTION"

# Name of the projects settings module.
# in this case is just settings and not the full path because it will change the dir to
# the project folder first.
export DJANGO_SETTINGS_MODULE="settings"

Шаг 2. Создайте скрипт ниже в / etc / default / celeryd и измените его разрешения с помощью

chmod +x /etc/init.d/celeryd 

Этот не нуждается в изменении. Источник

#!/bin/sh -e
# ============================================
#  celeryd - Starts the Celery worker daemon.
# ============================================
#
# :Usage: /etc/init.d/celeryd {start|stop|force-reload|restart|try-restart|status}
# :Configuration file: /etc/default/celeryd
#
# See http://docs.celeryq.org/en/latest/cookbook/daemonizing.html#init-script-celeryd


### BEGIN INIT INFO
# Provides:          celeryd
# Required-Start:    $network $local_fs $remote_fs
# Required-Stop:     $network $local_fs $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: celery task worker daemon
### END INIT INFO

#set -e

DEFAULT_PID_FILE="/var/run/celeryd@%n.pid"
DEFAULT_LOG_FILE="/var/log/celeryd@%n.log"
DEFAULT_LOG_LEVEL="INFO"
DEFAULT_NODES="celery"
DEFAULT_CELERYD="-m celery.bin.celeryd_detach"

# /etc/init.d/celeryd: start and stop the celery task worker daemon.

CELERY_DEFAULTS=${CELERY_DEFAULTS:-"/etc/default/celeryd"}

test -f "$CELERY_DEFAULTS" && . "$CELERY_DEFAULTS"
if [ -f "/etc/default/celeryd" ]; then
    . /etc/default/celeryd
fi

CELERYD_PID_FILE=${CELERYD_PID_FILE:-${CELERYD_PIDFILE:-$DEFAULT_PID_FILE}}
CELERYD_LOG_FILE=${CELERYD_LOG_FILE:-${CELERYD_LOGFILE:-$DEFAULT_LOG_FILE}}
CELERYD_LOG_LEVEL=${CELERYD_LOG_LEVEL:-${CELERYD_LOGLEVEL:-$DEFAULT_LOG_LEVEL}}
CELERYD_MULTI=${CELERYD_MULTI:-"celeryd-multi"}
CELERYD=${CELERYD:-$DEFAULT_CELERYD}
CELERYCTL=${CELERYCTL:="celeryctl"}
CELERYD_NODES=${CELERYD_NODES:-$DEFAULT_NODES}

export CELERY_LOADER

if [ -n "$2" ]; then
    CELERYD_OPTS="$CELERYD_OPTS $2"
fi

CELERYD_LOG_DIR=`dirname $CELERYD_LOG_FILE`
CELERYD_PID_DIR=`dirname $CELERYD_PID_FILE`
if [ ! -d "$CELERYD_LOG_DIR" ]; then
    mkdir -p $CELERYD_LOG_DIR
fi
if [ ! -d "$CELERYD_PID_DIR" ]; then
    mkdir -p $CELERYD_PID_DIR
fi

# Extra start-stop-daemon options, like user/group.
if [ -n "$CELERYD_USER" ]; then
    DAEMON_OPTS="$DAEMON_OPTS --uid=$CELERYD_USER"
    chown "$CELERYD_USER" $CELERYD_LOG_DIR $CELERYD_PID_DIR
fi
if [ -n "$CELERYD_GROUP" ]; then
    DAEMON_OPTS="$DAEMON_OPTS --gid=$CELERYD_GROUP"
    chgrp "$CELERYD_GROUP" $CELERYD_LOG_DIR $CELERYD_PID_DIR
fi

if [ -n "$CELERYD_CHDIR" ]; then
    DAEMON_OPTS="$DAEMON_OPTS --workdir=\"$CELERYD_CHDIR\""
fi


check_dev_null() {
    if [ ! -c /dev/null ]; then
        echo "/dev/null is not a character device!"
        exit 1
    fi
}


export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"


stop_workers () {
    $CELERYD_MULTI stop $CELERYD_NODES --pidfile="$CELERYD_PID_FILE"
}


start_workers () {
    $CELERYD_MULTI start $CELERYD_NODES $DAEMON_OPTS        \
                         --pidfile="$CELERYD_PID_FILE"      \
                         --logfile="$CELERYD_LOG_FILE"      \
                         --loglevel="$CELERYD_LOG_LEVEL"    \
                         --cmd="$CELERYD"                   \
                         $CELERYD_OPTS
}


restart_workers () {
    $CELERYD_MULTI restart $CELERYD_NODES $DAEMON_OPTS      \
                           --pidfile="$CELERYD_PID_FILE"    \
                           --logfile="$CELERYD_LOG_FILE"    \
                           --loglevel="$CELERYD_LOG_LEVEL"  \
                           --cmd="$CELERYD"                 \
                           $CELERYD_OPTS
}



case "$1" in
    start)
        check_dev_null
        start_workers
    ;;

    stop)
        check_dev_null
        stop_workers
    ;;

    reload|force-reload)
        echo "Use restart"
    ;;

    status)
        $CELERYCTL status $CELERYCTL_OPTS
    ;;

    restart)
        check_dev_null
        restart_workers
    ;;

    try-restart)
        check_dev_null
        restart_workers
    ;;

    *)
        echo "Usage: /etc/init.d/celeryd {start|stop|restart|try-restart|kill}"
        exit 1
    ;;
esac

exit 0

Шаг 3. Используйте эти команды для запуска, остановки и т. Д. Сценария.

# to start celeryd
/etc/init.d/celeryd start

# to stop
/etc/init.d/celeryd stop

# see the status
/etc/init.d/celeryd status

# print the log in the screen
cat /var/log/celery/w1.log  

Если у вас возникли проблемы, на сайте было множество комментариев и других рекомендаций. Надеюсь, это будет продолжаться долго.

0 голосов
/ 17 ноября 2011

Вы можете попробовать использовать Fat Controller, который может взять любой скрипт и демонизировать его. Он также может многократно запускать сценарии с интервалами, указанными в секундах, или вообще без интервала, поэтому он предотвратит одновременное выполнение двух экземпляров.

Он полностью написан на C, поэтому он очень стабилен, рассчитан на месяцы или годы - независимо от того, сколько ваших собственных скриптов может произойти сбой. Также очень легко начать работать.

Он также может выполнять гораздо больше задач, таких как параллельный запуск сценария, даже корректируя количество параллельных экземпляров в соответствии с объемом работы - но я думаю, это выходит за рамки вашего требования.

На сайте есть множество вариантов использования и подробные инструкции. Если вам понадобится дополнительная помощь, просто свяжитесь с нами или подайте заявку в службу поддержки, и я перезвоню вам, как только смогу.

Веб-сайт: http://fat -controller.sourceforge.net /

...