# Django - Celery, RabbitMQ, Supervisor ###### tags: `Django` `Celery` `RabbitMQ` `Supervisor` # Reference * [Celery Tutorial: A Must-Learn Technology for Python Developer](https://medium.com/swlh/python-developers-celery-is-a-must-learn-technology-heres-how-to-get-started-578f5d63fab3) --- # Supervisor 關於 Supervisor, 有 Linux 版, 也有 Python 版, 經測試後, 發現要使用 Linux 版, 而非使用 ``pip`` 去安裝 ## 安裝 Supervisor ``` sudo apt install supervisor ``` ``` 正在讀取套件清單... 完成 正在重建相依關係 正在讀取狀態資料... 完成 下列的額外套件將被安裝: python-meld3 python-pkg-resources 建議套件: python-setuptools supervisor-doc 下列【新】套件將會被安裝: python-meld3 python-pkg-resources supervisor ``` 安裝完成後, ``/etc/supervisor/conf.d`` 資料夾 與 ``/etc/supervisor/supervisord.conf`` 會被建立 --- # [Implementing Celery using Django for Background Task Processing](https://www.botreetechnologies.com/blog/implementing-celery-using-django-for-background-task-processing/) 建立 worker 與 beat 會用到的 supervisor ``*.conf``檔案 * ``sso_worker_supervisor.conf`` ``` ; ================================== ; celery worker supervisor ; ================================== ; the name of your supervisord program [program:sso_celery_worker] ; Set full path to celery program if using virtualenv command=/home/elite_lin/AWS/venv/bin/celery -A test_project2.celery worker --loglevel=debug ; The directory to your Django project directory=/home/elite_lin/AWS/sso_project/src ; If supervisord is run as the root user, switch users to this UNIX user account ; before doing any processing. user=elite_lin ; Supervisor will start as many instances of this program as named by numprocs numprocs=1 ; Put process stdout output in this file stdout_logfile=/var/log/celery/sso_worker.log ; Put process stderr output in this file stderr_logfile=/var/log/celery/sso_worker.log ; If true, this program will start automatically when supervisord is started autostart=true ; May be one of false, unexpected, or true. If false, the process will never ; be autorestarted. If unexpected, the process will be restart when the program ; exits with an exit code that is not one of the exit codes associated with this ; process’ configuration (see exitcodes). If true, the process will be ; unconditionally restarted when it exits, without regard to its exit code. autorestart=true ; The total number of seconds which the program needs to stay running after ; a startup to consider the start successful. startsecs=10 ; Need to wait for currently executing tasks to finish at shutdown. ; Increase this if you have very long running tasks. stopwaitsecs = 600 ; When resorting to send SIGKILL to the program to terminate it ; send SIGKILL to its whole process group instead, ; taking care of its children as well. killasgroup=true ; if your broker is supervised, set its priority higher ; so it starts first priority=998 ``` * ``sso_scheduler_supervisor.conf``: ``` ; ================================ ; celery beat supervisor ; ================================ ; the name of your supervisord program [program:sso_celery_beat] ; Set full path to celery program if using virtualenv command=/home/elite_lin/AWS/venv/bin/celery -A test_project2 beat --loglevel=debug ; The directory to your Django project directory=/home/elite_lin/AWS/sso_project/src ; If supervisord is run as the root user, switch users to this UNIX user account ; before doing any processing. user=elite_lin ; Supervisor will start as many instances of this program as named by numprocs numprocs=1 ; Put process stdout output in this file stdout_logfile=/var/log/celery/sso_beat.log ; Put process stderr output in this file stderr_logfile=/var/log/celery/sso_beat.log ; If true, this program will start automatically when supervisord is started autostart=true ; May be one of false, unexpected, or true. If false, the process will never ; be autorestarted. If unexpected, the process will be restart when the program ; exits with an exit code that is not one of the exit codes associated with this ; process’ configuration (see exitcodes). If true, the process will be ; unconditionally restarted when it exits, without regard to its exit code. autorestart=true ; The total number of seconds which the program needs to stay running after ; a startup to consider the start successful. startsecs=10 ; if your broker is supervised, set its priority higher ; so it starts first priority=999 ``` 將 ``sso_worker_supervisor.conf`` 與 ``sso_scheduler_supervisor.conf`` ``cp`` 到 ``/etc/supervisor/supervisord.conf`` 然後 建立 ``/var/log/celery`` 資料夾, 再建立2個空 log 檔: ``` cd /var/log/celery sudo touch sso_worker.log sudo touch sso_beat.log ``` 理論上,在執行下列3個指令後, ``` sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl status ``` 會看見 ``` sso_celery_beat RUNNING pid 10058, uptime 0:17:32 sso_celery_worker RUNNING pid 10057, uptime 0:17:32 ``` 若有 Error, 要去看指定的 log 檔中有什麼異常的資訊來除錯 ``` elite_lin@elite-lin-VirtualBox:/etc/supervisor$ ls conf.d supervisord.conf elite_lin@elite-lin-VirtualBox:/etc/supervisor$ elite_lin@elite-lin-VirtualBox:/etc/supervisor$ elite_lin@elite-lin-VirtualBox:/etc/supervisor$ sudo supervisorctl reread sso_celery_beat: available sso_celery_worker: available elite_lin@elite-lin-VirtualBox:/etc/supervisor$ elite_lin@elite-lin-VirtualBox:/etc/supervisor$ elite_lin@elite-lin-VirtualBox:/etc/supervisor$ sudo supervisorctl update sso_celery_worker: added process group sso_celery_beat: added process group elite_lin@elite-lin-VirtualBox:/etc/supervisor$ elite_lin@elite-lin-VirtualBox:/etc/supervisor$ elite_lin@elite-lin-VirtualBox:/etc/supervisor$ sudo supervisorctl status sso_celery_beat FATAL Exited too quickly (process log may have details) sso_celery_worker FATAL Exited too quickly (process log may have details) elite_lin@elite-lin-VirtualBox:/etc/supervisor$ elite_lin@elite-lin-VirtualBox:/etc/supervisor$ elite_lin@elite-lin-VirtualBox:/etc/supervisor$ sudo supervisorctl stop Error: stop requires a process name stop <name> Stop a process stop <gname>:* Stop all processes in a group stop <name> <name> Stop multiple processes or groups stop all Stop all processes elite_lin@elite-lin-VirtualBox:/etc/supervisor$ elite_lin@elite-lin-VirtualBox:/etc/supervisor$ elite_lin@elite-lin-VirtualBox:/etc/supervisor$ sudo supervisorctl start sso_celery_worker sso_celery_worker: ERROR (spawn error) ``` --- ``tasks.py``: ``` # created in 2021/01/15 from celery import task from django.core.mail import send_mail @task(name="send_request_access_mail") def send_request_access_mail(subject, message, sender, receivers): send_mail(subject, message, sender, receivers) ``` ``signal.py``: ``` from django.db.models.signals import post_save from django.dispatch import receiver from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_encode from django.template.loader import render_to_string # from .tokens import account_activation_signup_token # the app does not have that from django.conf import settings from .tasks import send_request_access_mail @receiver(post_save, sender=RequestAccessModel) def approval(sender, instance, created, **kwargs): if instance.accepted == True: subject = 'Activate Your MySite Account' message = render_to_string('request_access/request_approved.html', { 'user': instance, 'domain': 'localhost:8000', 'uid': urlsafe_base64_encode(force_bytes(instance.id)), 'token': 'aA1234567890', }) send_request_access_mail.delay(subject, message, settings.EMAIL_HOST_USER, [instance.email]) ``` --- # [Django Celery + RabbitMQ with Supervisor](https://riptutorial.com/django/example/32120/celery-plus-rabbitmq-with-supervisor) Celery requires a __broker__ to handle message-passing. We use __RabbitMQ__ because it’s easy to setup and it is well supported. Install rabbitmq using the following command ``` sudo apt-get install rabbitmq-server ``` Once the installation is complete, create user, add a virtual host and set permissions. ``` sudo rabbitmqctl add_user myuser mypassword sudo rabbitmqctl add_vhost myvhost sudo rabbitmqctl set_user_tags myuser mytag sudo rabbitmqctl set_permissions -p myvhost myuser ".*" ".*" ".*" ``` To start the server: ``` sudo rabbitmq-server ``` We can install ``celery`` with ``pip``: ``` pip install celery ``` In your Django ``settings.py`` file, your __broker URL__ would then look something like ``` BROKER_URL = 'amqp://myuser:mypassword@localhost:5672/myvhost' ``` Now start the celery worker ``` celery -A your_app worker -l info ``` This command start a Celery worker to run any tasks defined in your django app. __Supervisor__ is a Python program that allows you to control and keep running any unix processes. It can also restart crashed processes. We use it to make sure Celery workers are always running. First, Install supervisor ``` sudo apt-get install supervisor ``` Create ``your_proj.conf`` file in your supervisor ``conf.d`` (``/etc/supervisor/conf.d/your_proj.conf``): ``` [program:your_proj_celery] command=/home/your_user/your_proj/.venv/bin/celery --app=your_proj.celery:app worker -l info directory=/home/your_user/your_proj numprocs=1 stdout_logfile=/home/your_user/your_proj/logs/celery-worker.log stderr_logfile=/home/your_user/your_proj/logs/low-worker.log autostart=true autorestart=true startsecs=10 ``` Once our configuration file is created and saved, we can inform Supervisor of our new program through the ``supervisorctl`` command. First we tell Supervisor to look for any new or changed program configurations in the ``/etc/supervisor/conf.d`` directory with: ``` sudo supervisorctl reread ``` Followed by telling it to enact any changes with: ``` sudo supervisorctl update ``` Once our programs are running, there will undoubtedly be a time when we want to stop, restart, or see their status. ``` sudo supervisorctl status ``` For restart your celery instance: ``` sudo supervisorctl restart your_proj_celery ``` --- # [Celery + Supervisor With Django](https://gist.github.com/mau21mau/9371a95b7c14ddf7000c1827b7693801) --- # [django-celery - Celery Integration for Django](https://docs.celeryproject.org/projects/django-celery/en/stable/introduction.html) Version: 2.5.3 - 2021/01/15 django-celery 套件/ 模組 但這應不是我想要的結果 ---- # [Supervisor: A Process Control System](http://supervisord.org/) ## Introduction ### Overview Supervisor is a client/server system that allows its users to control a number of processes on UNIX-like operating systems. It was inspired by the following: * __Convenience__ It is often inconvenient to need to write ``rc.d`` scripts for every single process instance. ``rc.d`` scripts are a great lowest-common-denominator form of process initialization/autostart/management, but they can be painful to write and maintain. Additionally, ``rc.d`` scripts cannot automatically restart a crashed process and many programs do not restart themselves properly on a crash. Supervisord starts processes as its subprocesses, and can be configured to automatically restart them on a crash. It can also automatically be configured to start processes on its own invocation. * __Accuracy__ It’s often difficult to get accurate up/down status on processes on UNIX. Pidfiles often lie. Supervisord starts processes as subprocesses, so it always knows the true up/down status of its children and can be queried conveniently for this data. * __Delegation__ Users who need to control process state often need only to do that. They don’t want or need full-blown shell access to the machine on which the processes are running. Processes which listen on “low” TCP ports often need to be started and restarted as the root user (a UNIX misfeature). It’s usually the case that it’s perfectly fine to allow “normal” people to stop or restart such a process, but providing them with shell access is often impractical, and providing them with root access or sudo access is often impossible. It’s also (rightly) difficult to explain to them why this problem exists. If supervisord is started as root, it is possible to allow “normal” users to control such processes without needing to explain the intricacies of the problem to them. Supervisorctl allows a very limited form of access to the machine, essentially allowing users to see process status and control supervisord-controlled subprocesses by emitting “stop”, “start”, and “restart” commands from a simple shell or web UI. * __Process Groups__ Processes often need to be started and stopped in groups, sometimes even in a “priority order”. It’s often difficult to explain to people how to do this. Supervisor allows you to assign priorities to processes, and allows user to emit commands via the supervisorctl client like “start all”, and “restart all”, which starts them in the preassigned priority order. Additionally, processes can be grouped into “process groups” and a set of logically related processes can be stopped and started as a unit. ### Supervisor Components * __supervisord__ __The server piece of supervisor is named ``supervisord``__. It is responsible for starting child programs at its own invocation, responding to commands from clients, restarting crashed or exited subprocesseses, logging its subprocess stdout and stderr output, and generating and handling “events” corresponding to points in subprocess lifetimes. The server process uses a __configuration file__. This is typically located in ``/etc/supervisord.conf``. This configuration file is a “Windows-INI” style config file. __It is important to keep this file secure via proper filesystem permissions because it may contain unencrypted usernames and passwords__. * __supervisorctl__ The __command-line client piece of the supervisor is named ``supervisorctl``__. It provides a shell-like interface to the features provided by supervisord. From ``supervisorctl``, a user can connect to different ``supervisord`` processes (one at a time), get status on the subprocesses controlled by, stop and start subprocesses of, and get lists of running processes of a ``supervisord``. The command-line client talks to the server across a UNIX domain socket or an internet (TCP) socket. The server can assert that the user of a client should present authentication credentials before it allows him to perform commands. The client process typically uses the same configuration file as the server but any configuration file with a [supervisorctl] section in it will work. * __Web Server__ A (sparse) web user interface with functionality comparable to supervisorctl may be accessed via a browser if you start supervisord against an internet socket. Visit the server URL (e.g. http://localhost:9001/) to view and control process status through the web interface after activating the configuration file’s [inet_http_server] section. * __XML-RPC Interface__ The same HTTP server which serves the web UI serves up an XML-RPC interface that can be used to interrogate and control supervisor and the programs it runs. See XML-RPC API Documentation. ## [Installing to A System With Internet Access](http://supervisord.org/installing.html#installing-to-a-system-with-internet-access) ### Internet-Installing With Pip Supervisor can be installed with ``pip`` install: ``` pip install supervisor ``` Depending on the permissions of your system’s Python, you might need to be the root user to install Supervisor successfully using ``pip``. You can also install ``supervisor`` in a ``virtualenv`` via ``pip``. ---