# 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版本說明翻譯