From 4e770436719bb1db75c6273bc6299ad8a0ce6ce0 Mon Sep 17 00:00:00 2001 From: I Luk Kim Date: Thu, 16 Apr 2026 16:49:39 -0700 Subject: [PATCH] =?UTF-8?q?fix:=20=EB=B0=B1=EA=B7=B8=EB=9D=BC=EC=9A=B4?= =?UTF-8?q?=EB=93=9C=20reindex=20=EC=A0=84=EC=97=AD=20=EC=84=B8=EB=A7=88?= =?UTF-8?q?=ED=8F=AC=EC=96=B4(3)=20=EC=B6=94=EA=B0=80=20=E2=80=94=20?= =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EB=A3=A8=ED=94=84=20=ED=8F=AC?= =?UTF-8?q?=ED=99=94=20=EB=B0=A9=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 500+ 티커 bulk 스캔 시 ensure_future로 수백 개의 SEC EDGAR 태스크가 동시 생성되어 이벤트 루프 포화 → 서버 응답 불가. _BACKGROUND_REINDEX_SEMAPHORE(3)으로 동시 실행을 최대 3개로 제한. Co-Authored-By: Claude Sonnet 4.6 --- app/services/sec_filings_service.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/app/services/sec_filings_service.py b/app/services/sec_filings_service.py index 2d41737..3576c72 100644 --- a/app/services/sec_filings_service.py +++ b/app/services/sec_filings_service.py @@ -25,6 +25,10 @@ logger = logging.getLogger(__name__) # Maximum exhibit content size (5 MB) MAX_EXHIBIT_SIZE = 5 * 1024 * 1024 +# Limit concurrent background reindex tasks to prevent event-loop saturation +# when bulk scans trigger hundreds of simultaneous SEC EDGAR fetches. +_BACKGROUND_REINDEX_SEMAPHORE = asyncio.Semaphore(3) + class SECFilingsService: SUPPORTED_FORM_TYPES: Set[str] = { @@ -247,16 +251,17 @@ class SECFilingsService: self, ticker: str, form_types: Optional[Set[str]], lock: asyncio.Lock ) -> None: """Re-index a stale ticker in the background with its own DB session.""" - async with lock: - try: - from app.core.database import AsyncSessionLocal - async with AsyncSessionLocal() as session: - new_count = await self.index_filings( - session, ticker, form_types=form_types, skip_cache=True - ) - logger.info(f"Background reindex for {ticker}: {new_count} new filings") - except Exception as e: - logger.warning(f"Background reindex failed for {ticker}: {e}") + async with _BACKGROUND_REINDEX_SEMAPHORE: + async with lock: + try: + from app.core.database import AsyncSessionLocal + async with AsyncSessionLocal() as session: + new_count = await self.index_filings( + session, ticker, form_types=form_types, skip_cache=True + ) + logger.info(f"Background reindex for {ticker}: {new_count} new filings") + except Exception as e: + logger.warning(f"Background reindex failed for {ticker}: {e}") # ------------------------------------------------------------------ # search_filings: query DB with filters