perf(server): unblock event loop on rate-limit waits and markitdown
Two complementary changes to mitigate intermittent TLS handshake
timeouts and "notifications/cancelled: Bad Request" seen against the
single-worker uvicorn deployment.
1. bedesten rate-limiter back-pressure
- Add optional ``max_wait`` to ``_TokenBucket.acquire``: if the next
wait would exceed it, raise ``BedestenRateLimited`` immediately
instead of sleeping. After a server-side 429 the bucket pauses for
up to 30s; previously a queued request sat in ``asyncio.sleep``
for that whole window, holding the worker slot and pushing the
MCP client past its cancellation timeout.
- ``search_bedesten_unified`` / ``get_bedesten_document_markdown``
catch ``BedestenRateLimited`` and reuse the existing structured
429-style response, so callers get a fast, clean retry signal.
- Tunable via ``BEDESTEN_RATE_MAX_WAIT_S`` (default 8.0s).
2. Offload sync markitdown conversions to a thread
- Every ``markitdown.convert*`` call site is now wrapped in
``asyncio.to_thread(...)`` across 14 modules (bedesten, yargitay,
danistay, anayasa norm + bireysel, uyusmazlik, emsal, rekabet,
gib, kvkk, sayistay, bddk, sigorta_tahkim, kik_v2). PDF / large
HTML parsing was stalling the event loop for seconds, which on a
single-worker deployment delayed every other in-flight request
and queued new TLS handshakes until they timed out.
Verified locally:
- ``ast.parse`` + ``importlib.import_module`` on all 15 modified files
- ``mcp_server_main.create_app()`` constructs successfully
- New ``_TokenBucket.acquire(max_wait=...)`` smoke-tested across 6
paths: capacity-available, no-arg backward compat, max_wait raise,
max_wait wait+succeed, ``penalize_until`` + max_wait fast-raise.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
26aa3dacc6
commit
96a5a538b2
+38
-1
@@ -258,7 +258,7 @@ def create_app():
|
||||
|
||||
# --- Module Imports ---
|
||||
from yargitay_mcp_module.client import YargitayOfficialApiClient
|
||||
from bedesten_mcp_module.client import BedestenApiClient
|
||||
from bedesten_mcp_module.client import BedestenApiClient, BedestenRateLimited
|
||||
from bedesten_mcp_module.models import (
|
||||
BedestenSearchRequest, BedestenSearchData,
|
||||
BedestenDocumentMarkdown, BedestenCourtTypeEnum
|
||||
@@ -1182,6 +1182,26 @@ For best results, use exact phrases with quotes for legal terms."""),
|
||||
"page_size": pageSize,
|
||||
"searched_courts": court_types
|
||||
}
|
||||
except BedestenRateLimited as e:
|
||||
retry_after = f"{e.retry_after:.1f}"
|
||||
logger.warning(f"Bedesten local rate-limit bucket full for search; retry-after={retry_after}s")
|
||||
return {
|
||||
"decisions": [],
|
||||
"total_records": 0,
|
||||
"requested_page": pageNumber,
|
||||
"page_size": pageSize,
|
||||
"searched_courts": court_types,
|
||||
"error": "rate_limit_exceeded",
|
||||
"status_code": 429,
|
||||
"retry_after": retry_after,
|
||||
"message": (
|
||||
"Bedesten istemci tarafı eşzamanlılık sınırına ulaşıldı "
|
||||
"(yerel token-bucket dolu). Lütfen kısa bir süre bekleyip "
|
||||
"aramayı tekrar deneyin. Alternatif olarak yargi-cli aracını "
|
||||
"kullanabilirsiniz: https://github.com/saidsurucu/yargi-cli "
|
||||
"(kullanım talimatları için repo README'sini okuyun)."
|
||||
),
|
||||
}
|
||||
except httpx.HTTPStatusError as e:
|
||||
if e.response.status_code == 429:
|
||||
retry_after = e.response.headers.get("Retry-After", "")
|
||||
@@ -1227,6 +1247,23 @@ async def get_bedesten_document_markdown(
|
||||
|
||||
try:
|
||||
return await bedesten_client_instance.get_document_as_markdown(documentId)
|
||||
except BedestenRateLimited as e:
|
||||
retry_after = f"{e.retry_after:.1f}"
|
||||
logger.warning(f"Bedesten local rate-limit bucket full for document {documentId}; retry-after={retry_after}s")
|
||||
message = (
|
||||
"Bedesten istemci tarafı eşzamanlılık sınırına ulaşıldı "
|
||||
"(yerel token-bucket dolu). Lütfen kısa bir süre bekleyip "
|
||||
"belgeyi tekrar talep edin. Alternatif olarak yargi-cli aracını "
|
||||
"kullanabilirsiniz: https://github.com/saidsurucu/yargi-cli "
|
||||
"(kullanım talimatları için repo README'sini okuyun). "
|
||||
f"Retry-After: {retry_after}"
|
||||
)
|
||||
return BedestenDocumentMarkdown(
|
||||
documentId=documentId,
|
||||
markdown_content=f"ERROR (rate_limit_exceeded, HTTP 429): {message}",
|
||||
source_url=f"https://mevzuat.adalet.gov.tr/ictihat/{documentId}",
|
||||
mime_type=None,
|
||||
)
|
||||
except httpx.HTTPStatusError as e:
|
||||
if e.response.status_code == 429:
|
||||
retry_after = e.response.headers.get("Retry-After", "")
|
||||
|
||||
Reference in New Issue
Block a user