반복적인 서버 응답불능의 근본 원인 2가지를 해결:
1. BaseHTTPMiddleware → Pure ASGI 미들웨어 (app/middleware/error_logger.py)
- BaseHTTPMiddleware.call_next()가 요청당 asyncio task 2개 생성
- 20 동시연결 × 2 = 40 tasks → event loop scheduler 포화 → health check 타임아웃
- __call__(scope, receive, send) + send_wrapper 패턴으로 교체
- 요청당 단일 task, X-Request-ID 헤더 주입, 에러 응답 body 캡처 유지
- 불필요한 의존성 제거: BaseHTTPMiddleware, Request, Callable, get_db, AsyncSession
2. gc.collect() 추가 + --limit-max-requests 제거 (alpaca.py, docker-compose.yml)
- --limit-max-requests 500: 500요청 후 단일 worker 종료 → 서비스 gap 발생
- 대신 intraday 요청 처리 후 gc.collect()로 Python heap 명시적 회수
- 장시간 백필 중 메모리 누적 방지, worker 재시작 없이 안정 운영
3. Semaphore(3 → 5): BaseHTTPMiddleware 제거로 task 수 절반 → 처리량 복원
유지: mem_limit 2g, --limit-concurrency 20, Phase 4 경량 쿼리, request_logs 7일 retention
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
동시 Alpaca intraday 요청이 50개 이상 쌓이면 BaseHTTPMiddleware의
task 스케줄링 오버헤드로 이벤트 루프가 응답불능 상태가 되는 현상 수정.
- alpaca.py: _INTRADAY_SEMAPHORE(10) 추가 — /intraday, /intraday/today
양쪽 핸들러를 감쌈. 11번째 이후 요청은 세마포어 대기(비용 없음)
- docker-compose.yml: --limit-concurrency 100 추가 — 100개 초과 시
uvicorn이 503 반환, health 엔드포인트 보호
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
서비스 메서드가 db: AsyncSession을 인자로 받아 외부 API 호출(yfinance 30-60s,
Alpaca HTTP) 중에도 DB 커넥션을 잡고 있던 구조를 제거.
변경 패턴 (Session-per-phase):
Before: Endpoint(db) → Service(db) → DB check → API call(30s 세션 유지) → DB store
After: Endpoint() → Service() → DB check(세션1) → API call(세션 없음) → DB store(세션2)
변경 파일:
- alpaca_price_service.py: fetch_and_store_bars, get_or_fetch_multi_bars에서 db 제거
- price_data_service.py: get_or_update_price_data, get_multiple_tickers_data_optimized에서
db 제거; _fetch_price_data(새), _bulk_fetch_price_data(새, lambda 클로저 버그 수정);
_fetch_and_store_price_data, _bulk_fetch_and_store_price_data, get_multiple_tickers_data 제거
- alpaca.py, price.py: Depends(get_db) 제거 (GET /latest 제외)
- financial_service.py, real_sec_financial_service.py: 호출 인자 정리
결과: "idle in transaction" 커넥션 0개, 풀 고갈 원인 근본 해결
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
기존: end_date >= today 이면 무조건 400
변경: 장 마감(오후 4시 ET) 후에는 당일 날짜도 SIP로 조회 가능
- zoneinfo.ZoneInfo("America/New_York") 기반 ET 시각 체크
- 장 중 당일 요청 시 /intraday/today 안내 메시지
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
제거: /bars/{ticker}, /data/{ticker}, /intraday/{ticker}, /snapshot/{ticker}
유지:
- GET /alpaca/status
- GET /alpaca/intraday (SIP, 과거, 멀티 종목)
- GET /alpaca/intraday/today (IEX, 당일, 멀티 종목)
- GET /alpaca/snapshot (IEX, 단일/멀티 통합)
openapi.json 업데이트 (95 → 91 endpoints)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both GET /price/data and GET /alpaca/intraday:
- description에 배치 제한 설명 추가 (100개/요청, 자동 분할, 응답시간 선형 증가)
- 502 에러 메시지에 심볼 수 초과 가능성 힌트 추가
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GET /price/intraday (Yahoo Finance):
- 15분 지연, 1m=7일/5m-30m=60일/1h=730일 한계
- 백테스트 용도, 실시간 전략 부적합
GET /alpaca/intraday (Alpaca IEX):
- 실시간, IEX 피드 2~5% 커버리지
- 거래량 낮게 표시, 가격 레벨은 유사
- ORB 등 당일 실시간 전략 용도
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Same get_or_fetch_multi_bars() approach as daily bars:
- stores intraday rows in AlpacaPriceData (full timestamp as PK component)
- subsequent requests for historical periods served from DB
- same-day requests during market hours always hit Alpaca (max_date < end_dt)
- force_refresh=true bypasses DB check
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- GET /alpaca/snapshot/{ticker} — 단일 티커 실시간 가격/bid-ask/OHLCV/등락률
- GET /alpaca/snapshot?tickers=A,B — 최대 100개 멀티 티커 일괄 조회
- AlpacaClient.get_snapshot / get_snapshots 메서드 추가
- AlpacaSnapshotResponse / AlpacaMultiSnapshotResponse 스키마 추가
- docs/PYTHON_CLIENT.md 사용 예시 업데이트
- 캐시 없음 — 매 요청마다 Alpaca API 직접 호출
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- docs/DATA_COVERAGE.md 신규 생성: 엔드포인트별 실제 DB 보유 범위,
이론적 최대 범위, 백필 방법, SQL 확인 쿼리 포함
- FINRA/Alpaca/stocks/filings 엔드포인트 description에 데이터 범위 및
백필 방법 안내 추가 (Swagger UI에 표시됨)
현재 백필 필요 항목:
- FINRA: 2026-02-10~ 28거래일만 존재 → 2025년치 백필 권장
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Separate Alpaca price data into dedicated AlpacaPriceData table to avoid
UniqueConstraint('ticker', 'date') conflicts with Yahoo Finance PriceData.
Add Redis caching (build_cache_key/get_cached_response/set_cached_response)
to 3 Alpaca endpoints and 2 FINRA query endpoints with appropriate TTLs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>