refactor(discord): one liveness-knob resolver; int knobs reject inf and fractions

`_finite_positive_config_float` and `_config_int` were the same shape with the warn call
pasted six times and asymmetric sign checks. Collapse both onto `_liveness_knob(key, default,
cast)`: usable iff finite, >= 0 and exact for the cast; else warn and return 0; explicit 0
stays silent.

Two int-path holes closed on the way: `websocket_liveness_failure_threshold: .inf` raised
OverflowError inside `DiscordAdapter.__init__`, and `0.5` truncated to 0 and disabled the
probe silently — the bug class this PR exists to remove. `2.0` / `"2"` still resolve to 2.
This commit is contained in:
kshitijk4poor
2026-09-13 19:57:32 +05:30
committed by kshitij
parent 8dd0e80f29
commit 5dcd4844bd
2 changed files with 31 additions and 31 deletions
+19 -29
View File
@@ -1115,40 +1115,30 @@ class DiscordAdapter(DiscordMediaMixin, BasePlatformAdapter):
self.name, key, raw,
)
def _liveness_knob(self, key: str, default: Any, cast: type, *, env_key: Optional[str] = None):
"""Resolve a liveness knob: usable iff finite, >= 0 and exact for ``cast``; else warn and return 0.
``0`` is the documented opt-out and stays silent. Bools, unparsable strings, nan/inf,
negatives and (for int knobs) fractional values all disable the probe WITH a warning.
"""
raw = self._config_value(key, default, env_key=env_key)
try:
value = None if isinstance(raw, bool) else float(raw)
except (TypeError, ValueError):
value = None
if value is not None and math.isfinite(value) and value >= 0 and cast(value) == value:
return cast(value)
if value != 0:
self._warn_liveness_config_disabled(key, raw)
return cast(0)
def _finite_positive_config_float(
self, key: str, default: float, *, env_key: Optional[str] = None
) -> float:
"""Resolve a finite positive liveness duration; invalid values disable it (with a warning)."""
raw = self._config_value(key, default, env_key=env_key)
if isinstance(raw, bool):
self._warn_liveness_config_disabled(key, raw)
return 0.0
try:
value = float(raw)
except (TypeError, ValueError):
self._warn_liveness_config_disabled(key, raw)
return 0.0
if math.isfinite(value) and value > 0:
return value
if value != 0:
self._warn_liveness_config_disabled(key, raw)
return 0.0
return self._liveness_knob(key, default, float, env_key=env_key)
def _config_int(self, key: str, default: int, *, env_key: Optional[str] = None) -> int:
"""Resolve a positive liveness count; invalid values disable it (with a warning)."""
raw = self._config_value(key, default, env_key=env_key)
if isinstance(raw, bool):
self._warn_liveness_config_disabled(key, raw)
return 0
try:
value = int(raw)
except (TypeError, ValueError):
self._warn_liveness_config_disabled(key, raw)
return 0
if value < 0:
self._warn_liveness_config_disabled(key, raw)
return 0
return value
return self._liveness_knob(key, default, int, env_key=env_key)
def _handle_bot_task_done(self, task: asyncio.Task) -> None:
"""Surface post-startup discord.py task exits as a retryable fatal so GatewayRunner
+12 -2
View File
@@ -124,6 +124,8 @@ class _BrokenWebSocket:
("websocket_max_latency_seconds", "_max_latency_seconds", "-inf"),
("websocket_max_latency_seconds", "_max_latency_seconds", True),
("websocket_max_latency_seconds", "_max_latency_seconds", "15s"),
("websocket_liveness_failure_threshold", "_liveness_failure_threshold", 2.5),
("websocket_liveness_failure_threshold", "_liveness_failure_threshold", float("inf")),
],
)
def test_nonfinite_liveness_config_disables_that_probe_dimension(monkeypatch, key, attribute, raw):
@@ -149,6 +151,7 @@ def test_unusable_liveness_config_warns_instead_of_disabling_silently(caplog):
"websocket_liveness_interval_seconds": "15s",
"websocket_max_latency_seconds": True,
"websocket_liveness_failure_threshold": -1,
"websocket_heartbeat_ack_max_age_seconds": "nan",
},
)
)
@@ -156,8 +159,10 @@ def test_unusable_liveness_config_warns_instead_of_disabling_silently(caplog):
assert adapter._liveness_interval_seconds == 0.0
assert adapter._max_latency_seconds == 0.0
assert adapter._liveness_failure_threshold == 0
assert adapter._heartbeat_ack_max_age_seconds == 0.0
warned = [r.getMessage() for r in caplog.records if "liveness knob" in r.getMessage()]
assert len(warned) == 3
assert len(warned) == 4
assert any("websocket_heartbeat_ack_max_age_seconds='nan'" in w for w in warned)
assert any("websocket_liveness_interval_seconds='15s'" in w for w in warned)
assert any("websocket_max_latency_seconds=True" in w for w in warned)
assert any("websocket_liveness_failure_threshold=-1" in w for w in warned)
@@ -170,11 +175,16 @@ def test_explicit_zero_liveness_knob_disables_without_warning(caplog):
PlatformConfig(
enabled=True,
token="test-token",
extra={"websocket_liveness_interval_seconds": 0, "websocket_liveness_failure_threshold": 0},
extra={
"websocket_liveness_interval_seconds": 0,
"websocket_max_latency_seconds": "0",
"websocket_liveness_failure_threshold": 0,
},
)
)
assert adapter._liveness_interval_seconds == 0.0
assert adapter._max_latency_seconds == 0.0
assert adapter._liveness_failure_threshold == 0
assert not [r for r in caplog.records if "liveness knob" in r.getMessage()]