Extend WebSocket heartbeat grace
Raises the Socket.IO heartbeat interval and timeout defaults so long context and prompt work do not trip python-engineio's empty packet queue timeout. Adds positive-integer environment overrides and updates the runtime configuration regression test.
Alessandro committed
Jun 16, 2026 at 16:29 UTC
1dc719ff9c107beee4965b6946143e4b07b71f81
3 files changed
+40
-8
helpers/ui_server.py
+21
-2
@@ -37,6 +37,19 @@ from helpers.ws_manager import WsManager, set_shared_ws_manager
37
38
39
UPLOAD_LIMIT_BYTES = 5 * 1024 * 1024 * 1024
40
+SOCKETIO_PING_INTERVAL_SECONDS = 45
41
+SOCKETIO_PING_TIMEOUT_SECONDS = 120
42
+
43
+
44
+def _positive_int_env(name: str, default: int) -> int:
45
+ raw_value = os.getenv(name)
46
+ if raw_value is None:
47
+ return default
48
+ try:
49
+ value = int(raw_value)
50
+ except (TypeError, ValueError):
51
+ return default
52
+ return value if value > 0 else default
53
54
55
def configure_process_environment() -> None:
@@ -85,8 +98,14 @@ class UiServerRuntime:
98
cors_allowed_origins=lambda _origin, environ: validate_ws_origin(environ)[0],
99
logger=False,
100
engineio_logger=False,
88
- ping_interval=25,
89
- ping_timeout=20,
101
+ ping_interval=_positive_int_env(
102
+ "A0_SOCKETIO_PING_INTERVAL_SECONDS",
103
+ SOCKETIO_PING_INTERVAL_SECONDS,
104
+ ),
105
+ ping_timeout=_positive_int_env(
106
+ "A0_SOCKETIO_PING_TIMEOUT_SECONDS",
107
+ SOCKETIO_PING_TIMEOUT_SECONDS,
108
+ ),
109
max_http_buffer_size=50 * 1024 * 1024,
110
)
111
helpers/ui_server.py.dox.md
+4
-2
@@ -26,19 +26,21 @@
26
- `async serve_plugin_asset(self, plugin_name, asset_path)`
27
- `async serve_extension_asset(self, asset_path)`
28
- Top-level functions:
29
+- `_positive_int_env(name: str, default: int) -> int`
30
- `configure_process_environment() -> None`
30
-- Notable constants/configuration names: `UPLOAD_LIMIT_BYTES`.
31
+- Notable constants/configuration names: `UPLOAD_LIMIT_BYTES`, `SOCKETIO_PING_INTERVAL_SECONDS`, `SOCKETIO_PING_TIMEOUT_SECONDS`, `A0_SOCKETIO_PING_INTERVAL_SECONDS`, `A0_SOCKETIO_PING_TIMEOUT_SECONDS`.
32
33
## Runtime Contracts
34
35
- Helper modules own reusable framework APIs and must preserve public callers unless all callers, tests, and docs are updated together.
36
- Update this file whenever public functions, classes, persistence behavior, path/security assumptions, side effects, or cross-module contracts change.
37
+- Socket.IO heartbeat defaults are intentionally longer than Engine.IO's short defaults so CLI sessions survive long prompt/context work; environment overrides must remain positive integers and fall back to source defaults when invalid.
38
- Observed side-effect areas: filesystem reads, network calls, subprocess/runtime control, WebSocket state, plugin state, settings/state persistence, secret handling.
39
- Imported dependency areas include: `asyncio`, `dataclasses`, `datetime`, `flask`, `helpers`, `helpers.api`, `helpers.extension`, `helpers.files`, `helpers.print_style`, `helpers.server_startup`, `helpers.ws`, `helpers.ws_manager`, `logging`, `os`, `secrets`, `socketio`.
40
41
## Key Concepts
42
41
-- Important called helpers/classes observed in the source: `logging.getLogger.setLevel`, `Localization.get.apply_process_timezone`, `field`, `Flask`, `threading.RLock`, `socketio.AsyncServer`, `WsManager`, `set_shared_ws_manager`, `cls`, `server_runtime.refresh_runtime_settings`, `settings_helper.get_settings`, `settings_helper.set_runtime_settings_snapshot`, `self.ws_manager.set_server_restart_broadcast`, `UiRouteHandlers`, `self.webapp.add_url_rule`, `register_api_route`, `register_ws_namespace`, `files.read_file`, `render_template_string`, `session.pop`.
43
+- Important called helpers/classes observed in the source: `logging.getLogger.setLevel`, `Localization.get.apply_process_timezone`, `_positive_int_env`, `field`, `Flask`, `threading.RLock`, `socketio.AsyncServer`, `WsManager`, `set_shared_ws_manager`, `cls`, `server_runtime.refresh_runtime_settings`, `settings_helper.get_settings`, `settings_helper.set_runtime_settings_snapshot`, `self.ws_manager.set_server_restart_broadcast`, `UiRouteHandlers`, `self.webapp.add_url_rule`, `register_api_route`, `register_ws_namespace`, `files.read_file`, `render_template_string`, `session.pop`.
44
- Keep request/response, tool, or helper semantics documented here at the same time as source changes.
45
46
## Work Guidance
tests/test_run_ui_config.py
+15
-4
@@ -5,12 +5,23 @@ PROJECT_ROOT = Path(__file__).resolve().parents[1]
5
if str(PROJECT_ROOT) not in sys.path:
6
sys.path.insert(0, str(PROJECT_ROOT))
7
8
-import run_ui
8
+from helpers.ui_server import UiServerRuntime
9
10
11
def test_socketio_engine_configuration_defaults():
12
- server = run_ui.socketio_server.eio
12
+ server = UiServerRuntime.create().socketio_server.eio
13
14
- assert server.ping_interval == 25
15
- assert server.ping_timeout == 20
14
+ assert server.ping_interval == 45
15
+ assert server.ping_timeout == 120
16
+ assert server.max_http_buffer_size == 50 * 1024 * 1024
17
+
18
+
19
+def test_socketio_engine_configuration_uses_env_overrides(monkeypatch):
20
+ monkeypatch.setenv("A0_SOCKETIO_PING_INTERVAL_SECONDS", "30")
21
+ monkeypatch.setenv("A0_SOCKETIO_PING_TIMEOUT_SECONDS", "90")
22
+
23
+ server = UiServerRuntime.create().socketio_server.eio
24
+
25
+ assert server.ping_interval == 30
26
+ assert server.ping_timeout == 90
27
assert server.max_http_buffer_size == 50 * 1024 * 1024