问题
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.
回答1:
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']
回答2:
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.
回答3:
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