수정본
Some checks failed
CI/CD Pipeline / test-backend (push) Has been cancelled
CI/CD Pipeline / test-frontend (push) Has been cancelled
CI/CD Pipeline / build-and-push (push) Has been cancelled

This commit is contained in:
2026-03-27 14:47:49 +09:00
parent 844ee8944f
commit c818810667
25 changed files with 2708 additions and 266 deletions

View File

@@ -232,6 +232,7 @@ class KoreaInvestmentAPI:
# httpx 싱글톤 클라이언트 (커넥션 풀 재활용 — 매 요청마다 TCP/TLS 핸드셰이크 방지)
self._http_client: Optional[httpx.AsyncClient] = None
self._http_client_lock = asyncio.Lock()
# 토큰 발급 Lock (중복 발급 방지)
self._token_lock = asyncio.Lock()
@@ -250,7 +251,28 @@ class KoreaInvestmentAPI:
# 캐시된 토큰 로드
self._load_token_from_cache()
async def _get_http_client(self) -> httpx.AsyncClient:
"""싱글톤 httpx 클라이언트 반환. 없으면 생성."""
if self._http_client is None or self._http_client.is_closed:
async with self._http_client_lock:
if self._http_client is None or self._http_client.is_closed:
self._http_client = httpx.AsyncClient(
timeout=httpx.Timeout(10.0, connect=5.0),
limits=httpx.Limits(
max_connections=20,
max_keepalive_connections=10,
keepalive_expiry=30,
),
)
return self._http_client
async def close(self) -> None:
"""httpx 클라이언트 정리. 앱 종료 시 호출."""
if self._http_client and not self._http_client.is_closed:
await self._http_client.aclose()
self._http_client = None
def _load_token_from_cache(self):
"""파일에서 토큰 로드 (앱 시작 시 동기 호출)"""
try:
@@ -447,13 +469,13 @@ class KoreaInvestmentAPI:
# 타임아웃 설정
timeout = httpx.Timeout(self.timeout, connect=10.0)
async with httpx.AsyncClient(timeout=httpx.Timeout(10.0, connect=5.0)) as client:
response = await client.request(
method,
f"{self.base_url}{endpoint}",
headers=headers,
**kwargs
)
client = await self._get_http_client()
response = await client.request(
method,
f"{self.base_url}{endpoint}",
headers=headers,
**kwargs
)
# 성공
if response.status_code == 200: