djangoamazon-web-servicesamazon-elastic-beanstalkdjango-channelsdaphne

Issues with django-channels deployment on elastic-beanstalk


I am working on deploying my django app on Elastic Beanstalk using gunicorn for my wsgi and daphne to handle asgi. I managed to get my app deployed but the websockets are not functioning properly.

I was able to test that the EC2 instance connects to the redis cache by running the code below on my elastic beanstalk environment :

eb ssh

source /var/app/venv/*/bin/activate
cd /var/app/current/
python manage.py shell

>>> import channels.layers
>>> from asgiref.sync import async_to_sync
>>> channel_layer = channels.layers.get_channel_layer()
>>> async_to_sync(channel_layer.send)('test_channel', {'foo': 'bar'})
>>> async_to_sync(channel_layer.receive)('test_channel')
>>> {'foo': 'bar'} # <---------- I was able to receive a response

However, I was not able to run the initiate the daphne server on my EC2 instance manually : daphne -b 0.0.0.0 -p 5000 tattoovalley.asgi:application The code above generated the following error : ImproperlyConfigured( django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.

However I have configured the DJANGO_SETTINGS_MODULE environment module in my .ebextensions config file : .ebextensions/01_env.config

option_settings:  
    aws:elasticbeanstalk:environment:proxy:staticfiles:
        /static: static
        value: static/

    aws:elasticbeanstalk:container:python:     
        WSGIPath: tattoovalley/wsgi.py
    aws:elasticbeanstalk:application:environment:
        DJANGO_SETTINGS_MODULE: tattoovalley.settings
        PYTHONPATH: /opt/python/current/app/tattoovalley:$PYTHONPATH

    aws:elbv2:listener:80:
        DefaultProcess: http
        ListenerEnabled: 'true'
        Protocol: HTTP
        Rules: ws
    aws:elbv2:listenerrule:ws:
        PathPatterns: /ws/*
        Process: websocket
        Priority: 1
    aws:elasticbeanstalk:environment:process:http:
        Port: '80'
        Protocol: HTTP
    aws:elasticbeanstalk:environment:process:websocket:
        Port: '5000'
        Protocol: HTTP

enter image description here

I have also checked if the port 5000 is active and I did not find any activity.

What could be the problem ? Is there a solution that I can use to fix the websocket connection

UPDATED

Here is my asgi.py file :

import os
import django
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from django.core.asgi import get_asgi_application

from chat.routing import websocket_urlpatterns

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tattoovalley.settings")
django.setup()
django_asgi_app = get_asgi_application()

import chat.routing

application = ProtocolTypeRouter(
    {
        "http": django_asgi_app,
        "websocket": AllowedHostsOriginValidator(
            AuthMiddlewareStack(URLRouter(websocket_urlpatterns))
        ),
    }
)

Solution

  • Looking at your asgi.py file, I guess that you can make some changes:

    import os
    from django.core.asgi import get_asgi_application
    
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tattoovalley.settings")
    
    django_asgi_app = get_asgi_application()
    
    # Now you can safely import other Django-related modules
    from channels.auth import AuthMiddlewareStack
    from channels.routing import ProtocolTypeRouter, URLRouter
    from channels.security.websocket import AllowedHostsOriginValidator
    
    from chat.routing import websocket_urlpatterns
    
    import chat.routing    <---- NOT SURE IF YOU STILL NEED THIS
    
    application = ProtocolTypeRouter(
        {
            "http": django_asgi_app,
            "websocket": AllowedHostsOriginValidator(
                AuthMiddlewareStack(URLRouter(websocket_urlpatterns))
            ),
        }
    )
    

    I hope these changes make everything work. It basically comes down to the fact that you are trying to import 3th party Django packages/libraries, which aren't instantiated yet in your settings file. That needs to happen first before you can import them.

    Next to that, the import django && django.setup() are obsolete as far as I know.