후보 = watchlist(BE GET /api/v1/watchlist, timeout 5s) ∪ CURATED_SYMBOLS.
ThreadPoolExecutor(max_workers=5) 병렬 _safe_signal(실패 종목 제외).
BE 실패 시 큐레이션만으로 graceful. STK3-01·02 통합.
의존
선행: STK3-01, STK3-02
후행: STK3-06
롤백
라우터 비활성.
다이어그램
처리 흐름
sequenceDiagram
participant C as Client
participant M as main.py
participant BE as backend watchlist
participant P as ThreadPoolExecutor(5)
participant R as recommendation.py
C->>M: GET /recommendations?limit
M->>BE: GET /api/v1/watchlist (timeout 5s)
alt BE 성공
BE-->>M: symbols[]
else BE 실패 / 타임아웃
BE-->>M: [] (graceful)
end
Note over M: 후보 = watchlist ∪ CURATED_SYMBOLS
M->>P: _safe_signal(symbol) ×N 병렬
P-->>M: signals[] (실패 종목 제외)
M->>R: rank_recommendations(signals, limit)
M->>R: suggest_entry(each)
M-->>C: recommendations[]
클래스 의존
flowchart LR
subgraph Presentation["Presentation"]
router["main.py\n/recommendations 라우터"]
end
subgraph Application["Application"]
pool["ThreadPoolExecutor\n_safe_signal()"]
end
subgraph Domain["ML 도메인"]
rec["recommendation.py\nrank + suggest_entry"]
sig["signal.py"]
end
subgraph External["External"]
BE["BE /api/v1/watchlist"]
end
router --> pool
pool --> sig
router --> rec
router --> BE
테스트 케이스
BE watchlist 조회 실패(타임아웃) 시 큐레이션 종목만으로 추천 목록이 반환된다.
일부 종목 _safe_signal 실패 시 해당 종목이 결과에서 제외되고 나머지가 정상 반환된다.