ComfyUI/tests/test_retry_defaults.py
Glary-Bot b9abd21cb7 feat: make API node retry parameters configurable via environment variables
Adds COMFY_API_MAX_RETRIES, COMFY_API_RETRY_DELAY, and
COMFY_API_RETRY_BACKOFF environment variables that override the default
retry parameters for all API node HTTP requests (sync_op, sync_op_raw,
upload_file, download_url_to_bytesio).

Users in regions with unstable networks (e.g. behind the GFW in China)
can increase the retry budget to tolerate longer network interruptions:

  COMFY_API_MAX_RETRIES=10 COMFY_API_RETRY_DELAY=2.0 python main.py

Defaults remain unchanged (3 retries, 1.0s delay, 2.0x backoff) when
the env vars are not set.
2026-04-19 10:48:48 +00:00

95 lines
3.4 KiB
Python

"""Tests for configurable retry defaults via environment variables.
Verifies that COMFY_API_MAX_RETRIES, COMFY_API_RETRY_DELAY, and
COMFY_API_RETRY_BACKOFF environment variables are respected.
NOTE: Cannot import from comfy_api_nodes directly because the import
chain triggers CUDA initialization. The helpers under test are
reimplemented here identically to the production code in client.py.
"""
from __future__ import annotations
import os
from dataclasses import dataclass
from unittest.mock import patch
import pytest
def _env_int(key: str, default: int) -> int:
try:
return int(os.environ[key])
except (KeyError, ValueError):
return default
def _env_float(key: str, default: float) -> float:
try:
return float(os.environ[key])
except (KeyError, ValueError):
return default
@dataclass(frozen=True)
class _RetryDefaults:
max_retries: int = _env_int("COMFY_API_MAX_RETRIES", 3)
retry_delay: float = _env_float("COMFY_API_RETRY_DELAY", 1.0)
retry_backoff: float = _env_float("COMFY_API_RETRY_BACKOFF", 2.0)
class TestEnvHelpers:
def test_env_int_returns_default_when_unset(self):
with patch.dict(os.environ, {}, clear=True):
assert _env_int("NONEXISTENT_KEY", 42) == 42
def test_env_int_returns_env_value(self):
with patch.dict(os.environ, {"TEST_KEY": "10"}):
assert _env_int("TEST_KEY", 42) == 10
def test_env_int_returns_default_on_invalid_value(self):
with patch.dict(os.environ, {"TEST_KEY": "not_a_number"}):
assert _env_int("TEST_KEY", 42) == 42
def test_env_float_returns_default_when_unset(self):
with patch.dict(os.environ, {}, clear=True):
assert _env_float("NONEXISTENT_KEY", 1.5) == 1.5
def test_env_float_returns_env_value(self):
with patch.dict(os.environ, {"TEST_KEY": "2.5"}):
assert _env_float("TEST_KEY", 1.5) == 2.5
def test_env_float_returns_default_on_invalid_value(self):
with patch.dict(os.environ, {"TEST_KEY": "bad"}):
assert _env_float("TEST_KEY", 1.5) == 1.5
class TestRetryDefaults:
def test_hardcoded_defaults_match_expected(self):
defaults = _RetryDefaults()
assert defaults.max_retries == 3
assert defaults.retry_delay == 1.0
assert defaults.retry_backoff == 2.0
def test_env_vars_would_override_at_import_time(self):
"""Dataclass field defaults are evaluated at class-definition time.
This test verifies that _env_int/_env_float return the env values,
which is what populates the dataclass fields at import time."""
with patch.dict(os.environ, {"COMFY_API_MAX_RETRIES": "10"}):
assert _env_int("COMFY_API_MAX_RETRIES", 3) == 10
with patch.dict(os.environ, {"COMFY_API_RETRY_DELAY": "3.0"}):
assert _env_float("COMFY_API_RETRY_DELAY", 1.0) == 3.0
with patch.dict(os.environ, {"COMFY_API_RETRY_BACKOFF": "1.5"}):
assert _env_float("COMFY_API_RETRY_BACKOFF", 2.0) == 1.5
def test_explicit_construction_overrides_defaults(self):
defaults = _RetryDefaults(max_retries=10, retry_delay=3.0, retry_backoff=1.5)
assert defaults.max_retries == 10
assert defaults.retry_delay == 3.0
assert defaults.retry_backoff == 1.5
def test_frozen_dataclass(self):
defaults = _RetryDefaults()
with pytest.raises(AttributeError):
defaults.max_retries = 999