# Celery_Daemonization ###### tags: `celery` `celery 5.2` `python` [官方連結_Daemonization](https://docs.celeryq.dev/en/master/userguide/daemonizing.html) ## Daemonization 如今,多數Linux發行版本都利用systemd來管理系統與使用者服務的生命週期。 您可以通過輸入以下內容來檢查Linux發行版本是否使用systemd: ```shell $ 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](https://docs.celeryq.dev/en/master/userguide/daemonizing.html#daemon-systemd-generic)的文件以獲取指南。 然而,`init.d script`應該仍然可以在這些Linux發行版本上執行,因為systemd提供了`systemd-sysv`相容層,這可以從我們所提供的`init.d script`自動生成服務。 如果你為很多Linux發行版本打包Celery,並且有部份不支援systemd或其它Unix系統,你可以參考我們關於[init.d](https://docs.celeryq.dev/en/master/userguide/daemonizing.html#daemon-generic)的文件說明。 ### Generic init-scripts 參考[extra/generic-init.d/](https://github.com/celery/celery/tree/master/extra/generic-init.d/) 這個目錄包含**celery worker**程式通用的`bash init-scripts`,這應該執行在Linux、 FreeBSD、 OpenBSD與其它Unix-like平台上。 #### Init-script: celeryd **Usage:** /etc/init.d/celeryd {start|stop|restart|status} **Configuration file:** /etc/default/celeryd 配置這個script來正確的執行Worker,你可能最少要告訴它,啟動的時候目錄會改變到什麼位置。(找出包含你的應用程式的模組,或你的配置模組)。 常駐程式的腳本(daemonization script)由`/etc/default/celeryd`配置。這是一個`shell script`(**sh**),你可以像下面的配置選項來增加環境變數。要增加影響Worker的實際環境變數,你還需要`export`它們(例如,**export DISPLAY=":0"**) ##### Superuser privileges required `init-script`只能被root使用,而且這個shell配置文件也必須由root所擁有。 一般使用者並不需要使用`init-script`,他們反而可以使用**celery multi**(或**celery worker --detach**): ```shell $ celery multi start worker1 \ -A proj \ --pidfile="$HOME/run/celery/%n.pid" \ --logfile="$HOME/log/celery/%n%I.log" $ celery multi restart worker1 \ -A proj \ --logfile="$HOME/log/celery/%n%I.log" \ --pidfile="$HOME/run/celery/%n.pid $ celery multi stopwait worker1 --pidfile="$HOME/run/celery/%n.pid" ``` ##### Example configuration 這是一個Python專案的配置範例。 `/etc/default/celeryd:` ```python # Names of nodes to start # most people will only start one node: CELERYD_NODES="worker1" # but you can also start multiple and configure settings # for each in CELERYD_OPTS #CELERYD_NODES="worker1 worker2 worker3" # alternatively, you can specify the number of nodes to start: #CELERYD_NODES=10 # Absolute or relative path to the 'celery' command: CELERY_BIN="/usr/local/bin/celery" #CELERY_BIN="/virtualenvs/def/bin/celery" # App instance to use # comment out this line if you don't use an app CELERY_APP="proj" # or fully qualified: #CELERY_APP="proj.tasks:app" # Where to chdir at start. CELERYD_CHDIR="/opt/Myproject/" # Extra command-line arguments to the worker CELERYD_OPTS="--time-limit=300 --concurrency=8" # Configure node-specific settings by appending node name to arguments: #CELERYD_OPTS="--time-limit=300 -c 8 -c:worker2 4 -c:worker3 2 -Ofair:worker1" # Set logging level to DEBUG #CELERYD_LOG_LEVEL="DEBUG" # %n will be replaced with the first part of the nodename. CELERYD_LOG_FILE="/var/log/celery/%n%I.log" CELERYD_PID_FILE="/var/run/celery/%n.pid" # Workers should run as an unprivileged user. # You need to create this user manually (or you can choose # a user/group combination that already exists (e.g., nobody). CELERYD_USER="celery" CELERYD_GROUP="celery" # If enabled pid and log directories will be created if missing, # and owned by the userid/group configured. CELERY_CREATE_DIRS=1 ``` ##### Using a login shell 你可以利用`login shell`來繼承環境變數`CELERYD_USER`: ```shell CELERYD_SU_ARGS="-l" ``` 注意,並不建議這麼做,只有在絕對需要的時候才這麼做。 ##### Example Django configuration Django用戶現在使用與上面完全相同的樣板,不過,請確認該模組在定義Celery應用程式實例的時候有設置[DJANGO_SETTINGS_MODULE](https://django.readthedocs.io/en/latest/topics/settings.html#envvar-DJANGO_SETTINGS_MODULE)的預設值,如[First steps with Django](https://docs.celeryq.dev/en/master/django/first-steps-with-django.html#django-first-steps)的範例所述。 ##### Available options * CELERY_APP App instance to use (value for [--app](http://docs.celeryproject.org/en/master/reference/celery.bin.celery.html#cmdoption-celery-a) argument). * CELERY_BIN **celery**程式的絕對或相對路徑。範例: * celery * /usr/local/bin/celery * /virtualenvs/proj/bin/celery * /virtualenvs/proj/bin/python -m celery * CELERYD_NODES 要啟動的節點名稱(以空格區隔) * CELERYD_OPTS 提供Workers的額外參數,見`celery worker –help`提供的清單。它還支援`multi`用於為每個單獨節點配置設置的擴展語法。參考`celery multi –help`取得關於`multi-node`的配置範例。 * CELERYD_CHDIR 變更啟動路徑。預設為維持在當前目錄。 * CELERYD_PID_FILE PID文件的完整路徑。預設為`/var/run/celery/%n.pid` * CELERYD_LOG_FILE 日誌文件的完整路徑。預設為`/var/log/celery/%n%I.log`。注意,使用`%I`在使用prefork pool是非常重要的,因為multiple processes共享相同的日誌文件會導致資源競爭(race condition) * CELERYD_LOG_LEVEL Worker的記錄層級。預設為INFO. * CELERYD_USER 執行Woker的使用者身份。預設為當前使用者 * CELERYD_GROUP 執行Woker的群組。預設為當前使用者 * CELERY_CREATE_DIRS 總是建立目錄(log目錄與pid文件目錄)。預設只有在未設置自定義`logfile/pidfile`時建立目錄。 * CELERY_CREATE_RUNDIR 總是建立pidfile目錄。預設只有在未設置自定義pidfile位置時啟用 * CELERY_CREATE_LOGDIR 總是建立logfile目錄。預設只有在未設置自定義logfile位置時啟用 #### Init-script: celerybeat **Usage:** /etc/init.d/celerybeat {start|stop|restart} **Configuration file:** /etc/default/celerybeat or /etc/default/celeryd. ##### Example configuration 這是一個Python專案的配置範例: `/etc/default/celerybeat:` ```python # Absolute or relative path to the 'celery' command: CELERY_BIN="/usr/local/bin/celery" #CELERY_BIN="/virtualenvs/def/bin/celery" # App instance to use # comment out this line if you don't use an app CELERY_APP="proj" # or fully qualified: #CELERY_APP="proj.tasks:app" # Where to chdir at start. CELERYBEAT_CHDIR="/opt/Myproject/" # Extra arguments to celerybeat CELERYBEAT_OPTS="--schedule=/var/run/celery/celerybeat-schedule" ``` ##### Example Django configuration 你應該使用與上面相同的樣板,但是要確認變數`DJANGO_SETTINGS_MODULE`有設置(與匯出),並且將`CELERYD_CHDIR`設置為專案目錄: ```shell export DJANGO_SETTINGS_MODULE="settings" CELERYD_CHDIR="/opt/MyProject" ``` ##### Available options * CELERY_APP App instance to use (value for [--app](https://docs.celeryq.dev/en/master/reference/cli.html#cmdoption-celery-A)). * CELERYBEAT_OPTS **celery beat**的`additional arguments`,見**celery beat --help**查詢可用選項清單 * CELERYBEAT_PID_FILE 完整的PID檔案路徑。預設為`/var/run/celeryd.pid` * CELERYBEAT_LOG_FILE 完整的日誌文件路徑。預設為`/var/log/celeryd.log` * CELERYBEAT_LOG_LEVEL Log level to use. Default is INFO. * CELERYBEAT_USER 執行beat的使用者身份。預設為當前使用者。 * CELERYBEAT_GROUP 執行beat的群組。預設為當前使用者。 * CELERY_CREATE_DIRS 總是建立目錄(log目錄與pid文件目錄)。預設只有在未設置自定義`logfile/pidfile`時建立目錄。 * CELERY_CREATE_RUNDIR 總是建立pidfile目錄。預設只有在未設置自定義pidfile位置時啟用。 * CELERY_CREATE_LOGDIR 總是建立logfile目錄。預設只有在未設置自定義日logfile位置時啟用。 #### Troubleshooting 如果你無法讓`init-scripts`正常作業,那你應該試著在`verbose`模式執行它們: ```shell # sh -x /etc/init.d/celeryd start ``` 這可以確認為什麼服務無法啟動的提示。 如果Worker以"OK"開始,但幾乎是立即退出並且日誌文件沒有任何記錄,可能是存在錯誤,但是常駐程式標準輸出已經關閉,因此你無法在任何地方看到它們。對於這種情況,你可以使用環境變數**C_FAKEFORK**來跳過`daemonization`: ``` # C_FAKEFORK=1 sh -x /etc/init.d/celeryd start ``` 現在,你應該可以看的到錯誤訊息了。 通常,這類錯誤是由讀取或寫入權限不足所引起,也有可能是配置模組內的語法結構錯誤,使用者模組,第三方軟體,甚至是Celery本身。(如果你有發現bug,你應該[report it](http://docs.celeryproject.org/en/master/contributing.html#reporting-bugs)) ### Usage systemd * [extra/systemd/](https://github.com/celery/celery/tree/master/extra/systemd/) **Usage:** systemctl {start|stop|restart|status} celery.service **Configuration file:** /etc/conf.d/celery #### Service file: 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做為broker,你可以在[Unit] [systemd section](https://www.freedesktop.org/software/systemd/man/systemd.unit.html#%5BUnit%5D%20Section%20Options)中的`After=`與`Requires=`指定`rabbitmq-server.service`。 要配置`user`、`group`、**chdir**就要改變設定:`User, Group, WorkingDirectory`定義在`/etc/systemd/system/celery.service`。 你也可以使用systemd-tmpfiles,以便建立工作目錄(for logs and pid)。 **file:** `/etc/tmpfiles.d/celery.conf` ``` d /var/run/celery 0755 celery celery - d /var/log/celery 0755 celery celery - ``` ##### Example configuration 這是一個Python專案的配置範例: `/etc/conf.d/celery:` ``` # Name of nodes to start # here we have a single node CELERYD_NODES="w1" # or we could have three nodes: #CELERYD_NODES="w1 w2 w3" # Absolute or relative path to the 'celery' command: CELERY_BIN="/usr/local/bin/celery" #CELERY_BIN="/virtualenvs/def/bin/celery" # App instance to use # comment out this line if you don't use an app CELERY_APP="proj" # or fully qualified: #CELERY_APP="proj.tasks:app" # How to call manage.py CELERYD_MULTI="multi" # Extra command-line arguments to the worker CELERYD_OPTS="--time-limit=300 --concurrency=8" # - %n will be replaced with the first part of the nodename. # - %I will be replaced with the current child process index # and is important when using the prefork pool to avoid race conditions. CELERYD_PID_FILE="/var/run/celery/%n.pid" CELERYD_LOG_FILE="/var/log/celery/%n%I.log" CELERYD_LOG_LEVEL="INFO" # you may wish to add these options for Celery Beat CELERYBEAT_PID_FILE="/var/run/celery/beat.pid" CELERYBEAT_LOG_FILE="/var/log/celery/beat.log" ``` #### Service file: 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`,你應該執行**systemctldaemon-reload**,以便Systemd確認該文件。每次你修正之後也要執行一下。如果你在系統啟動(重啟)之後能夠自動啟動celery beat的服務,請使用**systemctl enable celerybeat.service**。 ### Running the worker with superuser privileges (root) 使用superuser權限來執行Worker是非常危險的做法。應該有一個做法來避免使用root執行。Celery可以在使用pickle序列化的消息中運行任意的程式碼-這是危險的,特別是以root執行的時候。 預設情況下,Celery不會以root來執行Workers。相關的錯誤訊息也許在日誌記錄中不可見,但如果使用`C_FAKEFORK`,那可能會看的到。 使用`C_FORCE_ROOT`強制Celery以root執行Worker。 在沒有使用`C_FORCE_ROOT`以root執行情況下,Worker會顯示"OK",但會沒有任何錯誤訊息,立即退出。在新開發或生產環境(無意間)以root身份執行,可能會發生這個問題。 ### supervisor * [extra/supervisord/](https://github.com/celery/celery/tree/master/extra/supervisord/) ### launchd (macOS) * [extra/macOS](https://github.com/celery/celery/tree/master/extra/macOS/) ## History 20190822_依據4.4版本說明翻譯 20220520_依據5.2版本說明翻譯