First of all, sorry for the long question, I hope a few of you have patience for this.
TL; DR: How do I load django settings correctly in systemd?
I am following this guide, Deploying Django Channels Using Daphne, so I can run some real-time apps (using WebSockets). Without nginx, and running from the command line the worker (python manage.py runworker) and interface (daphne), I can access the correct channels consumer class, as can be seen in the log below (these were triggered from a javascript client):
2017-10-09 21:10:35,210 - DEBUG - worker - Got message on websocket.connect (reply daphne.response.CYeWgnNQoY!mwuQrazQtv)
2017-10-09 21:10:35,211 - DEBUG - runworker - websocket.connect
2017-10-09 21:10:35,211 - DEBUG - worker - Dispatching message on websocket.connect to api.consumers.OrderConsumer
2017-10-09 21:10:48,132 - DEBUG - worker - Got message on websocket.receive (reply daphne.response.CYeWgnNQoY!mwuQrazQtv)
2017-10-09 21:10:48,132 - DEBUG - runworker - websocket.receive
2017-10-09 21:10:48,132 - DEBUG - worker - Dispatching message on websocket.receive to api.consumers.OrderConsumer
These events were triggered by the following javascript calls:
ws = new WebSocket("ws://localhost:8000/order/1/")
ws.send("test")
With nginx, and running both interface and worker on systemd, I get the following log despite using the exact same trigger input.
2017-10-09 20:38:35,503 - DEBUG - worker - Got message on websocket.connect (reply daphne.response.PPGuXtBmQD!EgUfaNZjUj)
2017-10-09 20:38:35,503 - DEBUG - runworker - websocket.connect
2017-10-09 20:38:35,503 - DEBUG - worker - Dispatching message on websocket.connect to channels.routing.connect_consumer
2017-10-09 20:38:42,993 - DEBUG - worker - Got message on websocket.receive (reply daphne.response.PPGuXtBmQD!EgUfaNZjUj)
2017-10-09 20:38:42,993 - DEBUG - runworker - websocket.receive
2017-10-09 20:38:42,993 - DEBUG - worker - Dispatching message on websocket.receive to channels.routing.null_consumer
Please note that the receive channel is being routed to a null_consumer
. I believe the problem here is simply the fact that channels.routing
is not being well setup. Since I use the same setting (Django settings file) in both versions, this probably means that the setting itself is not being correctly loaded. Please consider the following files.
## rest-api/farmaApp/settings.py
...
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'asgi_redis.RedisChannelLayer',
'CONFIG': {
'hosts': [('localhost', 6379)],
},
'ROUTING': 'farmaApp.routing.channel_routing',
}
}
...
Which should setup channels.routing
to:
## rest-api/farmaApp/routing.py
from channels.routing import route
from api.consumers import ws_connect, ws_disconnect, OrderConsumer
channel_routing = [
route('websocket.connect', ws_connect, path=r'^/users/'),
route('websocket.disconnect', ws_disconnect, path=r'^/users/'),
OrderConsumer.as_route(path=r'^/order/(?P<order_id>[\d+])/'),
]
Again, I don't think the configuration itself is wrong, as it works without systemd. Finally, here are my systemd configs:
## /etc/systemd/system/daphne.service
[Unit]
Description=daphne daemon
After=network.target
[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/rest-api
Environment=DJANGO_SETTINGS_MODULE=farmaApp.settings
ExecStart=/home/ubuntu/rest-api/env/bin/daphne --access-log /home/ubuntu/rest-api/access.log -b 0.0.0.0 -p 8001 farmaApp.asgi:channel_layer
[Install]
WantedBy=multi-user.target
## /etc/systemd/system/django_worker.service
[Unit]
Description=django_worker daemon
After=network.target
[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/rest-api
Environment=DJANGO_SETTINGS_MODULE=farmaApp.settings
ExecStart=/home/ubuntu/rest-api/env/bin/python manage.py runworker -v 2
[Install]
WantedBy=multi-user.target
Note on both config files that I export to the environment the DJANGO_SETTINGS_MODULE variable as according to the linked guide. I believe this isn't working as expected.
I've just deployed my django channel app, and the following systemd service file worked for me without using supervisor:
/etc/systemd/system/django-channels-daphne.service
[Unit]
Description=daphne server script for my project
After=network.target
[Service]
User=webuser
Group=webuser
WorkingDirectory=/path/to/myproject
Environment=DJANGO_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Environment=DJANGO_ALLOWED_HOSTS=myapp.chatbot.ai
ExecStart=/path/to/python/virtualenv/bin/daphne -b 0.0.0.0 -p 8000 myproject.asgi:channel_layer
Restart=always
[Install]
WantedBy=multi-user.target
/etc/systemd/system/django-channels-runworker.service
[Unit]
Description=python runworker server for myproject
After=network.target
[Service]
User=webuser
Group=webuser
WorkingDirectory=/path/to/myproject
Environment=DJANGO_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Environment=DJANGO_ALLOWED_HOSTS=myapp.chatbot.ai
ExecStart=/path/to/python/virtualenv/bin/python /path/to/myproject/manage.py runworker --threads 4
Restart=always
[Install]
WantedBy=multi-user.target
/path/to/myproject/myproject/asgi.py
import os
import channels
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
channel_layer = channels.asgi.get_channel_layer()
Some lines in /path/to/myproject/myproject/settings.py:
ALLOWED_HOSTS = [os.environ['DJANGO_ALLOWED_HOSTS']]
SECRET_KEY = os.environ['DJANGO_SECRET_KEY']
Yes, supervisord did work. Key bits of the /etc/supervisor/conf.d/project_name.conf were (some further links in the commented portions):
[program:platform_asgi_daphne]
; # https://stackoverflow.com/questions/17055951/how-to-set-environment-variables-in-supervisor-service
; # https://github.com/django/daphne/pull/37
; # https://wiki.cac.washington.edu/display/infra/Extracting+Certificate+and+Private+Key+Files+from+a+.pfx+File
; # daphne -e ssl:8443:privateKey=localhost.key:certKey=localhost.crt <channel_layer>
environment =
DJANGO_SECRET_KEY='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
DJANGO_DEBUG='True'
directory=/path/to/project/
; # http://channels.readthedocs.io/en/stable/deploying.html
; command=/path/to/venv/bin/daphne --port 80 --bind 0.0.0.0 classact.asgi:channel_layer
command=/path/to/venv/bin/daphne -e ssl:443:privateKey=../keys/server.key:certKey=../keys/server.crt --bind 0.0.0.0 projectfoldername.asgi:channel_layer
;user=webapps
;group=webapps
user=root
group=webapps
[program:platform_asgi_workers]
; # https://github.com/django/channels/issues/408#issuecomment-276384104
environment =
DJANGO_SECRET_KEY='xxxxxxxxxxxxxxxxxxxxxxxxx',
DJANGO_DEBUG='True'
command=/path/to/venv/bin/python /path/to/project/manage.py runworker
process_name=asgi_worker%(process_num)s
numprocs=2
;user=webapps
user=root
group=webapps
I had a couple of issues running as the user webapps which have yet to be sorted out so they run as root (writing to an encrypted folder with odd perms). I didn't get to the point where I wasn't repeating a bunch of environment vars in each section (there is probably a way). There are several others there like the database, user, static root etc depending on the platform (prod or dev).
I also have some certs to deal with so that is shown as well (if not needed take out the ssl parts). Also note running two workers.
In your posted configs the daphne port seems to be off.
you wrote:
ws = new WebSocket("ws://localhost:8000/order/1/")
ws.send("test")`
while using 8001 in your systemd startup file
ExecStart=/home/ubuntu/rest-api/env/bin/daphne --access-log /home/ubuntu/rest-api/access.log -b 0.0.0.0 -p 8001 farmaApp.asgi:channel_layer
来源:https://stackoverflow.com/questions/46655488/running-django-channels-with-daphne-on-systemd