From bb03cc4525d5b36dc99a031805d5edbbf805c299 Mon Sep 17 00:00:00 2001 From: gahusb Date: Mon, 18 May 2026 21:37:49 +0900 Subject: [PATCH] perf(signal_v2): raise stock_client TTL for NAS load relief (SP-A1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit portfolio 60s → 180s (3분 폴링 → 3회당 1회 fetch) news-sent 300s → 600s (sentiment는 자주 안 바뀜) screener 60s → 300s (Top-20 분 단위 변화 미미) V2 재시작 시점부터 NAS stock에 대한 인바운드 호출이 분당 12 → 분당 3~4 로 감소 예상. 캐시 hit ratio 0~50% → 66~80%. 회귀 테스트 3건 추가로 미래 의도치 않은 TTL 변경 차단. Also update test_stock_client.py fake_time assertions from 61.0 → 181.0 to match the new 180s portfolio TTL (tests were TTL-dependent). Co-Authored-By: Claude Opus 4.7 (1M context) --- signal_v2/stock_client.py | 9 +++++---- signal_v2/tests/test_stock_client.py | 10 +++++----- signal_v2/tests/test_stock_client_ttl.py | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 signal_v2/tests/test_stock_client_ttl.py diff --git a/signal_v2/stock_client.py b/signal_v2/stock_client.py index 668b62c..25ec7f4 100644 --- a/signal_v2/stock_client.py +++ b/signal_v2/stock_client.py @@ -9,11 +9,12 @@ import httpx logger = logging.getLogger(__name__) -# Cache TTL by endpoint (seconds) +# Cache TTL by endpoint (seconds). +# 2026-05-18 — NAS 인바운드 호출 부담 완화 (Plan-A SP-A1). _TTL = { - "portfolio": 60.0, - "news-sentiment": 300.0, - "screener-preview": 60.0, + "portfolio": 180.0, # 3분 (1분 폴링 시 3 폴링당 1회 실제 fetch) + "news-sentiment": 600.0, # 10분 (뉴스 sentiment는 자주 안 바뀜) + "screener-preview": 300.0, # 5분 (Top-20은 분 단위로 거의 안 바뀜) } # Retry policy diff --git a/signal_v2/tests/test_stock_client.py b/signal_v2/tests/test_stock_client.py index 54bb9ab..b3ceab3 100644 --- a/signal_v2/tests/test_stock_client.py +++ b/signal_v2/tests/test_stock_client.py @@ -34,7 +34,7 @@ async def test_get_portfolio_normal_returns_dict_with_pnl_pct(mock_stock_api): async def test_get_portfolio_uses_cache_within_ttl(mock_stock_api): - """60s TTL 내 두번째 호출 = mock 콜 1회.""" + """180s TTL 내 두번째 호출 = mock 콜 1회.""" route = mock_stock_api.get("/api/webai/portfolio").mock( return_value=httpx.Response( 200, json={"holdings": [], "cash": [], "summary": {}} @@ -56,7 +56,7 @@ async def test_get_portfolio_refetches_after_ttl_expiry(mock_stock_api, monkeypa 200, json={"holdings": [], "cash": [], "summary": {}} ) ) - # Fake clock: starts at 0, jumps to 61 between calls + # Fake clock: starts at 0, jumps past portfolio TTL (180s) between calls fake_time = [0.0] monkeypatch.setattr( "signal_v2.stock_client.time.monotonic", lambda: fake_time[0] @@ -65,7 +65,7 @@ async def test_get_portfolio_refetches_after_ttl_expiry(mock_stock_api, monkeypa client = StockClient(BASE_URL, API_KEY) try: await client.get_portfolio() - fake_time[0] = 61.0 # 60s TTL 만료 + fake_time[0] = 181.0 # 180s TTL 만료 await client.get_portfolio() assert route.call_count == 2 finally: @@ -152,8 +152,8 @@ async def test_get_portfolio_falls_back_to_stale_on_all_failures( first = await client.get_portfolio() assert first["holdings"][0]["ticker"] == "005930" - # Advance fake clock past TTL (60s) so cache is stale - fake_time[0] = 61.0 + # Advance fake clock past TTL (180s) so cache is stale + fake_time[0] = 181.0 # Now mock to return 500s persistently route1.mock(return_value=httpx.Response(500, text="server error")) diff --git a/signal_v2/tests/test_stock_client_ttl.py b/signal_v2/tests/test_stock_client_ttl.py new file mode 100644 index 0000000..1ab2fba --- /dev/null +++ b/signal_v2/tests/test_stock_client_ttl.py @@ -0,0 +1,18 @@ +# tests/test_stock_client_ttl.py +"""SP-A1 회귀 — _TTL이 NAS 부담 완화를 위한 값으로 설정되어 있어야 함.""" +from signal_v2.stock_client import _TTL + + +def test_portfolio_ttl_is_180s(): + """portfolio TTL은 180초 이상 (3분 폴링에서 1회 fetch가 3 폴링 커버).""" + assert _TTL["portfolio"] >= 180.0 + + +def test_news_sentiment_ttl_is_600s(): + """news-sentiment TTL은 600초 이상 (10분, 뉴스 sentiment는 자주 안 바뀜).""" + assert _TTL["news-sentiment"] >= 600.0 + + +def test_screener_preview_ttl_is_300s(): + """screener-preview TTL은 300초 이상 (5분, Top-20은 분 단위로 거의 안 바뀜).""" + assert _TTL["screener-preview"] >= 300.0