Django Channels redis.exceptions.TimeoutError: Timeout reading from 127.0.0.1:6379

My program worked fine when using InMemoryChannelLayer, but now that I've switched to redis just opening the WebSocket (not even sending or receiving any messages) causes a timeout error. Redis cli ping returns a pong, and

$ python manage.py shell
import channels.layers
channel_layer = channels.layers.get_channel_layer()
from asgiref.sync import async_to_sync
async_to_sync(channel_layer.send)('test_channel', {'type': 'hello'})
async_to_sync(channel_layer.receive)('test_channel')

Works exactly like I'd expect. My Settings looks like

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': { "hosts": [('127.0.0.1', 6379)] },
    },
}

My Consumers.py

class DashboardConsumer(WebsocketConsumer):
    def connect(self):
        # Triggered when a client opens a WebSocket connection
        self.accept()  
    def receive(self, text_data):
        # Triggered every time the client sends a message
        data = json.loads(text_data)
        message = data["message"]
        self.send(text_data=json.dumps({"message": message}))

WebsocketConsumer is the synchronous variant, so every consumer method runs in a thread pool. channels_redis is asyncio-based, and its connection is bound to the event loop that created it. Switch to the async consumer.

from channels.generic.websocket import AsyncWebsocketConsumer

class DashboardConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        await self.accept()

    async def receive(self, text_data):
        data = json.loads(text_data)
        await self.send(text_data=json.dumps({"message": data["message"]}))

Also confirm channels_redis version. 4.x renamed the backend, and channels_redis.core.RedisChannelLayer still exists but channels_redis.pubsub.RedisPubSubChannelLayer is the recommended one now and avoids a class of timeout issues:

'BACKEND': 'channels_redis.pubsub.RedisPubSubChannelLayer',

The fact that your channel_layer.send/receive works fine in manage.py shell but the WebSocket times out is the classic signature: Redis itself is reachable, but your ASGI application isn't being invoked. Django is almost certainly serving the traffic via standard WSGI (which handles HTTP but silently drops WebSockets) instead of ASGI.

Here are the four things you need to check in your configuration, in order:

1. ASGI_APPLICATION Setting

Ensure you have explicitly pointed Django to your ASGI setup inside your main settings.py file. Without this, the web framework defaults to WSGI:

ASGI_APPLICATION = "myproject.asgi.application"

2. Missing ProtocolTypeRouter in asgi.py

Verify that your asgi.py file is explicitly mapping the websocket protocol type to your application routing layout:

import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
import myproject.routing

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")

application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    "websocket": AuthMiddlewareStack(
        URLRouter(myproject.routing.websocket_urlpatterns)
    ),
})

3. Server Component Ordering

If you are running the application via python manage.py runserver, ensure that daphne is listed at the very top of your INSTALLED_APPS block, explicitly before django.contrib.staticfiles. If it is placed after it, the legacy WSGI development server takes control and ignores the WebSocket routing definitions completely.

4. channels_redis Host Definition

If you have upgraded to channels_redis version 4.0 or newer, the channel layer configurations heavily prefer raw connection URLs over old-school host tuples. Update your CHANNEL_LAYERS block to match this structure:

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "CONFIG": {
            "hosts": ["redis://127.0.0.1:6379"],
        },
    },
}
Вернуться на верх