diff --git a/api/extensions/ext_socketio.py b/api/extensions/ext_socketio.py index 887734c8b8d..78ff7576287 100644 --- a/api/extensions/ext_socketio.py +++ b/api/extensions/ext_socketio.py @@ -20,9 +20,14 @@ def _get_ssl_cert_reqs() -> ssl.VerifyMode: def _build_redis_options(redis_url: str) -> dict[str, Any]: - """Build Redis options for Socket.IO's cross-process pub/sub manager.""" + """Build Redis options for Socket.IO's cross-process pub/sub manager. + + Note: ``socket_timeout`` is intentionally omitted. The RedisManager runs a + blocking ``pubsub.listen()`` loop that idles indefinitely between messages; + applying a read timeout there causes a reconnect storm (issue #39423). + ``socket_connect_timeout`` still guards connection establishment. + """ options: dict[str, Any] = { - "socket_timeout": dify_config.REDIS_SOCKET_TIMEOUT, "socket_connect_timeout": dify_config.REDIS_SOCKET_CONNECT_TIMEOUT, "health_check_interval": dify_config.REDIS_HEALTH_CHECK_INTERVAL, "protocol": dify_config.REDIS_SERIALIZATION_PROTOCOL, diff --git a/api/tests/unit_tests/extensions/test_ext_socketio.py b/api/tests/unit_tests/extensions/test_ext_socketio.py index f9f85106960..20271d1516f 100644 --- a/api/tests/unit_tests/extensions/test_ext_socketio.py +++ b/api/tests/unit_tests/extensions/test_ext_socketio.py @@ -31,3 +31,15 @@ def test_build_redis_options_includes_tls_options_for_rediss(monkeypatch) -> Non assert options["ssl_ca_certs"] == "/ca.pem" assert options["ssl_certfile"] == "/cert.pem" assert options["ssl_keyfile"] == "/key.pem" + + +def test_build_redis_options_omits_socket_timeout(monkeypatch) -> None: + # socket_timeout must not be passed to RedisManager because the pub/sub + # listen loop blocks indefinitely between messages; a read timeout there + # triggers an infinite reconnect storm (issue #39423). + monkeypatch.setattr(ext_socketio.dify_config, "REDIS_SOCKET_TIMEOUT", 5.0) + + options = ext_socketio._build_redis_options("redis://redis.example.com:6380/3") + + assert "socket_timeout" not in options + assert "socket_connect_timeout" in options