From 2420d41864e10e23d2a544431881527c0e2fe4f3 Mon Sep 17 00:00:00 2001 From: Federico Capoano Date: Thu, 27 Aug 2026 19:33:33 -0300 Subject: [PATCH 1/4] [fix] Configured django-channels without Redis timeouts --- images/common/openwisp/settings.py | 6 +++++- tests/runtests.py | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/images/common/openwisp/settings.py b/images/common/openwisp/settings.py index e74f3ab0..82dc9ce1 100644 --- a/images/common/openwisp/settings.py +++ b/images/common/openwisp/settings.py @@ -229,7 +229,11 @@ CHANNEL_LAYERS = { "default": { "BACKEND": "channels_redis.core.RedisChannelLayer", - "CONFIG": {"hosts": [CHANNEL_REDIS_HOST]}, + "CONFIG": { + "hosts": [ + {"address": CHANNEL_REDIS_HOST, "socket_timeout": None}, + ], + }, }, } diff --git a/tests/runtests.py b/tests/runtests.py index 3cbf9b2b..bdcdba2b 100644 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -1,3 +1,4 @@ +import json import os import subprocess import tempfile @@ -64,6 +65,19 @@ def test_wait_for_services(self): class Test1Dashboard(BaseTestUtils, unittest.TestCase): + def test_dashboard_channels_redis_socket_timeout(self): + channel_redis_url = "redis://redis:6379/1" + output, _ = self._execute_django_shell_command( + "from django.conf import settings; import json; print(json.dumps(" + "settings.CHANNEL_LAYERS['default']['CONFIG']['hosts'][0]))", + environment={"CHANNEL_REDIS_URL": channel_redis_url}, + ) + self.assertEqual( + json.loads(output.strip().splitlines()[-1]), + {"address": channel_redis_url, "socket_timeout": None}, + "Channels Redis host must have an unlimited socket timeout.", + ) + def test_dashboard_uses_same_origin_api_urls(self): """Ensure dashboard browser requests use module default relative URLs.""" output, _ = self._execute_django_shell_command( From 1ddfbf59f222b0c8db8e7bdf9d722f34e95cb2ad Mon Sep 17 00:00:00 2001 From: Federico Capoano Date: Thu, 27 Aug 2026 19:43:56 -0300 Subject: [PATCH 2/4] [chores] Addressed review feedback --- images/common/openwisp/settings.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/images/common/openwisp/settings.py b/images/common/openwisp/settings.py index 82dc9ce1..608fccac 100644 --- a/images/common/openwisp/settings.py +++ b/images/common/openwisp/settings.py @@ -231,7 +231,13 @@ "BACKEND": "channels_redis.core.RedisChannelLayer", "CONFIG": { "hosts": [ - {"address": CHANNEL_REDIS_HOST, "socket_timeout": None}, + { + "address": CHANNEL_REDIS_HOST, + # Redis>=8 changed the default timeout of read + # operations to 5 seconds, which breaks django-channels, + # hence we need to explicitly remove the timeout. + "socket_timeout": None, + }, ], }, }, From 55239c1ba098d1787bcb4aeeedc1d275c1018507 Mon Sep 17 00:00:00 2001 From: Federico Capoano Date: Thu, 27 Aug 2026 19:48:24 -0300 Subject: [PATCH 3/4] [chores] Addressed review feedback --- tests/runtests.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/runtests.py b/tests/runtests.py index bdcdba2b..10109ed8 100644 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -65,19 +65,6 @@ def test_wait_for_services(self): class Test1Dashboard(BaseTestUtils, unittest.TestCase): - def test_dashboard_channels_redis_socket_timeout(self): - channel_redis_url = "redis://redis:6379/1" - output, _ = self._execute_django_shell_command( - "from django.conf import settings; import json; print(json.dumps(" - "settings.CHANNEL_LAYERS['default']['CONFIG']['hosts'][0]))", - environment={"CHANNEL_REDIS_URL": channel_redis_url}, - ) - self.assertEqual( - json.loads(output.strip().splitlines()[-1]), - {"address": channel_redis_url, "socket_timeout": None}, - "Channels Redis host must have an unlimited socket timeout.", - ) - def test_dashboard_uses_same_origin_api_urls(self): """Ensure dashboard browser requests use module default relative URLs.""" output, _ = self._execute_django_shell_command( @@ -149,6 +136,19 @@ def test_dashboard_excludes_disabled_radius_api_urls(self): "Dashboard must not serve disabled RADIUS API URLs.", ) + def test_dashboard_channels_redis_socket_timeout(self): + channel_redis_url = "redis://redis:6379/1" + output, _ = self._execute_django_shell_command( + "from django.conf import settings; import json; print(json.dumps(" + "settings.CHANNEL_LAYERS['default']['CONFIG']['hosts'][0]))", + environment={"CHANNEL_REDIS_URL": channel_redis_url}, + ) + self.assertEqual( + json.loads(output.strip().splitlines()[-1]), + {"address": channel_redis_url, "socket_timeout": None}, + "Channels Redis host must have an unlimited socket timeout.", + ) + class TestServices(FunctionalTestUtils, unittest.TestCase): custom_static_token = None From 7f0ef03d1ebf15a9c2b3ff4258580cade8d90f41 Mon Sep 17 00:00:00 2001 From: Federico Capoano Date: Thu, 27 Aug 2026 19:54:16 -0300 Subject: [PATCH 4/4] [chores] Addressed review feedback [skip ci] --- images/common/openwisp/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/common/openwisp/settings.py b/images/common/openwisp/settings.py index 608fccac..89e1410b 100644 --- a/images/common/openwisp/settings.py +++ b/images/common/openwisp/settings.py @@ -233,7 +233,7 @@ "hosts": [ { "address": CHANNEL_REDIS_HOST, - # Redis>=8 changed the default timeout of read + # redis-py 8.0.0 changed the default timeout of socket # operations to 5 seconds, which breaks django-channels, # hence we need to explicitly remove the timeout. "socket_timeout": None,