Django now working channels with ASGI + WSGI in Heroku - django

I am trying to setup a Django + Heroku app with Channels (V.2).
I tried to follow all the tutorial but most of them are not updated.
App must use WSGI for HTTP request and ASGI for websockets requests.
So far I found that it is almost working, the last missing piece is for the websockets endpoints to be visible for web app.
At this point whenever I try to create a new websocket:
Error during WebSocket handshake: Unexpected response code: 404
Here is the Settings:
ASGI_APPLICATION = 'app_xxx.routing.application'
ASGI_THREADS = 5
WSGI_APPLICATION = 'app_xxx.wsgi.application'
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
'hosts': [os.environ.get('REDIS_URL')],
},
},
}
Here is the Procfile:
web: gunicorn app_xxx.wsgi --log-file -
web2: daphne app_xxx.asgi:channel_layer --port $PORT --bind 0.0.0.0 -v2
worker: python manage.py runworker channel_layer -v2
Here is the asgi:
import os
from channels.layers import get_channel_layer
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app_xxx.settings")
channel_layer = get_channel_layer()
Here is the routing:
from channels.routing import ProtocolTypeRouter, URLRouter, ChannelNameRouter
from django.urls import path
from apps.booking.consumers import BookingConsumer
application = ProtocolTypeRouter({
"websocket": URLRouter([
path('ws/booking_review/<room_name>', BookingConsumer),
]),
})

You're supposed to run the ASGI application, not channel layer. Your ASGI_APPLICATION setting should point to routing.py or you can move its contents to asgi.py and point to it. With your current configuration, your Procfile should look like this:
web: gunicorn app_xxx.wsgi --log-file -
web2: daphne app_xxx.routing:application --port $PORT --bind 0.0.0.0 -v2
worker: python manage.py runworker channel_layer -v2
Check the docs deployment page for more details

Related

File upload working when executing flask command but doesn't work using uwsgi

So I have this basic setup:
hello.py
from flask import Flask, request
from os import environ
app = Flask(__name__)
#app.route("/", methods=['POST'])
def hello():
return repr(request.files)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8080)
wsgi.py
from hello import app
if __name__ == "__main__":
app.run()
Request is HTTP POST from nodejs.
Running flask command...
FLASK_APP="uwsgi.py" PYTHONUNBUFFERED=1 FLASK_ENV=development flask run --port=8080 --host=0.0.0.0
...output is:
ImmutableMultiDict([('file', <FileStorage: 'screenshot.png' ('image/png')>)])
Running uwsgi command...
venv/bin/uwsgi --http 0.0.0.0:8080 --plugin python --wsgi-file uwsgi.py --callable app --master --processes 4 --threads 2
..output is empty dict
ImmutableMultiDict([])

Heroku flask + socket.io 400 BAD REQUEST

Hello im trying to deploy my flask app on heroku. Im using flask_socketio module and socket.io in version 4.5(i didn't know how to initialize in 2.3.x version - io())
Here's my flask code:
from flask import Flask, render_template, url_for, redirect, session, request, jsonify
from flask_socketio import SocketIO
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
socketio = SocketIO(app)
#secret key etc...
...
#socketio.on('message')
def handle_msg(msg):
socketio.send('Syncing...')
if __name__ == '__main__':
socketio.run(app)
Here's my javascript:
...
export const socket = io();
socket.connect('https://proman-code-cool.herokuapp.com/');
function init() {
...
//live sync
socket.on('message', function(msg) {
console.log(msg);
boardsManager.reloadBoards(userId);
});
}
init();
And what i want is to make real-time sync to other users after adding something. And this is working locally but on heroku ive got all the time similar errors to:
When i've changed my Procfile to web: gunicorn -k eventlet main:app and with installed eventlet 0.30.2 i've got errors like class uri 'eventlet' invalid or not found. I can't find anywhere solution for that.
eventlet==0.30.2 in requirements.txt and python-3.8.13 in runtime.txt did the job!
Procfile: web: gunicorn --worker-class eventlet -w 1 main:app

Deployment of Django Channels App in Google Cloud Platform

I am working on my first django channels app and I want to deploy my django channel app in Google Cloud Platform,its working fine in local server,but when I deployed it on Google Cloud Platform,it gives me errors:
WebSocket connection to 'wss://sockets-263709.appspot.com/ws/chat/user2/' failed: Error during WebSocket handshake: Unexpected response code: 400
I have researched but can't figure out how to setup it,here's my below code:
Entry point:
from Frames.wsgi import application
app = application
wsgi.py:
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Frames.settings')
application = get_wsgi_application()
Asgi.py
import os
import django
from channels.routing import get_default_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Frames.settings')
django.setup()
application = get_default_application()
settings.py:
WSGI_APPLICATION = 'Frames.wsgi.application'
ASGI_APPLICATION = "Frames.routing.application"
CHANNEL_LAYERS={
"default":{
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("sockets-263709.appspot.com", 6379)],
},
},
}
client side:
var wsStart='ws://';
// check if it is secured then assign wss://
if (loc.protocol==='https:'){
wsStart="wss://"
}
var chatSocket = new WebSocket(wsStart +window.location.host +
'/ws/chat/' + roomName + '/');
Requirements.txt
absl-py==0.8.1
aioredis==1.3.1
asgiref==3.2.3
astor==0.8.1
async-timeout==3.0.1
attrs==19.3.0
autobahn==19.11.1
Automat==0.8.0
certifi==2019.11.28
cffi==1.13.2
channels==2.3.1
channels-redis==2.4.1
chardet==3.0.4
constantly==15.1.0
daphne==2.4.0
Django==3.0.1
djangochannelsrestframework==0.0.3
djangorestframework==3.11.0
gast==0.3.2
google-pasta==0.1.8
grpcio==1.25.0
h5py==2.10.0
hiredis==1.0.1
hyperlink==19.0.0
idna==2.8
incremental==17.5.0
Markdown==3.1.1
msgpack==0.6.2
mysqlclient==1.4.6
protobuf==3.11.1
pyasn1==0.4.8
pyasn1-modules==0.2.7
pycparser==2.19
PyHamcrest==1.9.0
PyMySQL==0.9.3
pyOpenSSL==19.1.0
pytz==2019.3
PyYAML==5.2
requests==2.22.0
scipy==1.3.3
service-identity==18.1.0
six==1.13.0
sqlparse==0.3.0
termcolor==1.1.0
tqdm==4.40.2
Twisted==19.10.0
txaio==18.8.1
urllib3==1.25.7
I have a start point from WSGI.py,I have researched and came know about daphne but don't know,can anybody point me how to deploy it properly.The connection is successfully open in locally.
Is the host is correctly mention in config(CHANNEL_LAYERS) in settings.py

Gevent pywsgi server used with gunicorn?

I have a flask app setup to use the gevent WSGIServer in my code. I am also running gunicorn on the command line to start the server.
Should I be using WSGI server in the code when also running with gunicorn? Currently looks like this:
from flask import Flask
from gevent.pywsgi import WSGIServer
application = Flask(__name__)
#application.route("/")
def hello():
return "hello"
if __name__ == '__main__':
port = int(os.environ.get('PORT', 5000))
WSGIServer(('', port), application).serve_forever()
On the command line I am running gunicorn like:
gunicorn -w 4 myapp:application
Do I need the WSGIServer in my code, or just run it as application.run() on the default flask server?
According to Standalone WSGI Containers, The gunicorn and gevent.pywsgi are both WSGI Containers, and the gunicorn only reconize the entry named application.
So the code below if __name__ == '__main__': is not useful anymore.
If you want to use gevent,you could do:
gunicorn -k gevent -w 4 myapp:application

Django Gevent integration

How to integrate Gevent with Django framework, What settings has to be modified in the Settings.py and wsgi.py files for the integration.
I want to start gevent http server(port 8000) and gevent web socket server(port 9000) from the Django.
The easiest way is to use Gunicorn and tell it to use the gevent worker class. The Gunicorn docs are pretty good. For Django 1.4 or later the recommended way to start Gunicorn is simply to call the WSGI interface like so:
gunicorn --worker-class gevent wsgi:application
If you don't care about all the nice features of Gunicorn (like graceful restarts for no-downtime upgrades for example) you can use the gevent wsgi server directly. I do this myself to save some memory for non-critical websites that can be down for a little while during upgrades. This is my "run_gevent.py" file, it should be fairly easy to grok:
import gevent.monkey; gevent.monkey.patch_all()
import os, socket
from gevent.socket import socket as gsocket
from gevent.pywsgi import WSGIServer
from django.core.handlers.wsgi import WSGIHandler
script_dir = os.path.dirname(os.path.abspath(__file__))
pid_filename = os.path.join(script_dir, 'server.pid')
socket_filename = os.path.join(script_dir, 'server.sock')
pidfile = open(pid_filename, 'w')
pidfile.write(str(os.getpid()) + str('\n'))
pidfile.close()
server_socket = gsocket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
os.remove(socket_filename)
except OSError:
pass
server_socket.bind(socket_filename)
server_socket.listen(256)
os.environ['DJANGO_SETTINGS_MODULE'] = 'project.settings'
server = WSGIServer(listener = server_socket, application = WSGIHandler(), log = None)
server.serve_forever(stop_timeout = 3)