mirror of
https://github.com/Comfy-Org/ComfyUI.git
synced 2026-08-25 18:32:35 +08:00
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.
This commit is contained in:
94
tests/test_retry_defaults.py
Normal file
94
tests/test_retry_defaults.py
Normal file
@@ -0,0 +1,94 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user