fix: uvicorn 미설치 시 dashboard 오해 없는 실패 처리 (#178) #184
12
src/main.py
12
src/main.py
@@ -1300,10 +1300,18 @@ def _start_dashboard_server(settings: Settings) -> threading.Thread | None:
|
|||||||
if not settings.DASHBOARD_ENABLED:
|
if not settings.DASHBOARD_ENABLED:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# Validate dependencies before spawning the thread so startup failures are
|
||||||
|
# reported synchronously (avoids the misleading "started" → "failed" log pair).
|
||||||
|
try:
|
||||||
|
import uvicorn # noqa: F401
|
||||||
|
from src.dashboard import create_dashboard_app # noqa: F401
|
||||||
|
except ImportError as exc:
|
||||||
|
logger.warning("Dashboard server unavailable (missing dependency): %s", exc)
|
||||||
|
return None
|
||||||
|
|
||||||
def _serve() -> None:
|
def _serve() -> None:
|
||||||
try:
|
try:
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
from src.dashboard import create_dashboard_app
|
from src.dashboard import create_dashboard_app
|
||||||
|
|
||||||
app = create_dashboard_app(settings.DB_PATH)
|
app = create_dashboard_app(settings.DB_PATH)
|
||||||
@@ -1314,7 +1322,7 @@ def _start_dashboard_server(settings: Settings) -> threading.Thread | None:
|
|||||||
log_level="info",
|
log_level="info",
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning("Dashboard server failed to start: %s", exc)
|
logger.warning("Dashboard server stopped unexpectedly: %s", exc)
|
||||||
|
|
||||||
thread = threading.Thread(
|
thread = threading.Thread(
|
||||||
target=_serve,
|
target=_serve,
|
||||||
|
|||||||
@@ -2194,6 +2194,29 @@ def test_start_dashboard_server_enabled_starts_thread() -> None:
|
|||||||
mock_thread.start.assert_called_once()
|
mock_thread.start.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
def test_start_dashboard_server_returns_none_when_uvicorn_missing() -> None:
|
||||||
|
"""Returns None (no thread) and logs a warning when uvicorn is not installed."""
|
||||||
|
settings = Settings(
|
||||||
|
KIS_APP_KEY="test_key",
|
||||||
|
KIS_APP_SECRET="test_secret",
|
||||||
|
KIS_ACCOUNT_NO="12345678-01",
|
||||||
|
GEMINI_API_KEY="test_gemini_key",
|
||||||
|
DASHBOARD_ENABLED=True,
|
||||||
|
)
|
||||||
|
import builtins
|
||||||
|
real_import = builtins.__import__
|
||||||
|
|
||||||
|
def mock_import(name: str, *args: object, **kwargs: object) -> object:
|
||||||
|
if name == "uvicorn":
|
||||||
|
raise ImportError("No module named 'uvicorn'")
|
||||||
|
return real_import(name, *args, **kwargs)
|
||||||
|
|
||||||
|
with patch("builtins.__import__", side_effect=mock_import):
|
||||||
|
thread = _start_dashboard_server(settings)
|
||||||
|
|
||||||
|
assert thread is None
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# market_outlook BUY confidence threshold tests (#173)
|
# market_outlook BUY confidence threshold tests (#173)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user