本番環境で大規模言語モデル(LLM)を運用する際、同時に複数のリクエストを処理する必要があるケースは必ず訪れます。しかし、すべてのAI APIプロバイダーは同時接続数(concurrency limit)に上限を設けており、この制限がシステム全体のスループットを制約するボトルネックとなります。

私は複数の本番プロジェクトで、この同時接続数制限导致的パフォーマンス問題を日々最適化してきました。本稿では、代表的な4つの突破手法を архитектура設計からパフォーマンス、そしてコスト最適化の観点から深く比較し、あなたのユースケースに最適な選択を指南します。

同時接続数制限が生まれる根本原因

AI APIプロバイダーが同時接続数に制限を設ける理由は主に3つです:

この制限を突破しないまま高負荷運用すると、リクエストが503 Service Unavailableで拒否され、ユーザー体験が大きく損なわれます。

同時接続数制限突破の4つの主要アプローチ

1. リクエストキューイング(Request Queuing)

最もシンプルな手法です。リクエストをFIFOキューに溜め込み、プロバイダーの同時接続数に合わせて逐次処理します。

import asyncio
import aiohttp
from collections import deque
from dataclasses import dataclass, field
from typing import Optional
import time

@dataclass
class QueuedRequest:
    prompt: str
    result: Optional[str] = None
    error: Optional[str] = None
    enqueued_at: float = field(default_factory=time.time)
    completed_at: Optional[float] = None

class RequestQueue:
    def __init__(
        self,
        api_key: str,
        base_url: str = "https://api.holysheep.ai/v1",
        max_concurrent: int = 5,
        rate_limit_per_minute: int = 60
    ):
        self.api_key = api_key
        self.base_url = base_url
        self.max_concurrent = max_concurrent
        self.rate_limit = rate_limit_per_minute / 60  # per second
        self.queue: deque[QueuedRequest] = deque()
        self.semaphore = asyncio.Semaphore(max_concurrent)
        self.last_request_time = 0
        self._lock = asyncio.Lock()

    async def _rate_limit_wait(self):
        """レート制限を遵守するための待機"""
        async with self._lock:
            min_interval = 1.0 / self.rate_limit
            elapsed = time.time() - self.last_request_time
            if elapsed < min_interval:
                await asyncio.sleep(min_interval - elapsed)
            self.last_request_time = time.time()

    async def _execute_request(
        self,
        session: aiohttp.ClientSession,
        request: QueuedRequest
    ) -> QueuedRequest:
        async with self.semaphore:
            await self._rate_limit_wait()
            
            headers = {
                "Authorization": f"Bearer {self.api_key}",
                "Content-Type": "application/json"
            }
            
            payload = {
                "model": "gpt-4.1",
                "messages": [{"role": "user", "content": request.prompt}],
                "max_tokens": 1000
            }
            
            try:
                async with session.post(
                    f"{self.base_url}/chat/completions",
                    json=payload,
                    headers=headers,
                    timeout=aiohttp.ClientTimeout(total=60)
                ) as response:
                    if response.status == 200:
                        data = await response.json()
                        request.result = data["choices"][0]["message"]["content"]
                    else:
                        error_text = await response.text()
                        request.error = f"HTTP {response.status}: {error_text}"
            except Exception as e:
                request.error = str(e)
            
            request.completed_at = time.time()
            return request

    async def enqueue(self, prompt: str) -> QueuedRequest:
        """リクエストをキューに追加"""
        request = QueuedRequest(prompt=prompt)
        self.queue.append(request)
        return request

    async def process_all(
        self,
        progress_callback: Optional[callable] = None
    ) -> list[QueuedRequest]:
        """キュー内の全リクエストを処理"""
        connector = aiohttp.TCPConnector(limit=self.max_concurrent)
        async with aiohttp.ClientSession(connector=connector) as session:
            tasks = []
            for request in self.queue:
                task = asyncio.create_task(
                    self._execute_request(session, request)
                )
                tasks.append(task)
                
                if progress_callback:
                    progress_callback(len(tasks), len(self.queue))
            
            results = await asyncio.gather(*tasks)
            return list(results)

使用例

async def main(): queue = RequestQueue( api_key="YOUR_HOLYSHEEP_API_KEY", max_concurrent=5, rate_limit_per_minute=60 ) # 100件のリクエストをキューに追加 for i in range(100): await queue.enqueue(f"リポート {i+1} のサマリーを生成してください") # 進捗表示付きで処理 def show_progress(completed, total): print(f"進捗: {completed}/{total} ({completed*100//total}%)") results = await queue.process_all(progress_callback=show_progress) # 結果の確認 successful = sum(1 for r in results if r.result) failed = sum(1 for r in results if r.error) avg_time = sum( r.completed_at - r.enqueued_at for r in results if r.completed_at ) / len(results) print(f"成功: {successful}, 失敗: {failed}") print(f"平均処理時間: {avg_time:.2f}秒") asyncio.run(main())

この手法の長所は実装のシンプルさです。短所はチェーン全体の処理時間が接続数上限に律速される点です。

2. リクエストバッチング(Request Batching)

複数のリクエストを1つのバッチに統合し、1回のAPI呼び出しで処理します。これは特にHolySheep AIのbatch APIで効率的に実装できます。

import asyncio
import aiohttp
import json
from typing import list
from dataclasses import dataclass
import hashlib

@dataclass
class BatchJob:
    job_id: str
    prompts: list[str]
    results: list[Optional[str]] = None
    status: str = "pending"

class BatchProcessor:
    def __init__(
        self,
        api_key: str,
        base_url: str = "https://api.holysheep.ai/v1"
    ):
        self.api_key = api_key
        self.base_url = base_url
        self.headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        }

    def _create_job_id(self, prompts: list[str]) -> str:
        """プロンプトのハッシュからjob_idを生成"""
        content = json.dumps(prompts, sort_keys=True)
        return hashlib.sha256(content.encode()).hexdigest()[:16]

    async def create_batch_job(self, prompts: list[str]) -> str:
        """
        バッチジョブを作成(HolySheep batch API使用)
        最大50件のプロンプトを1バッチにまとめ可能
        """
        job_id = self._create_job_id(prompts)
        
        # HolySheep Batch APIへのリクエスト構築
        requests = []
        for idx, prompt in enumerate(prompts):
            requests.append({
                "custom_id": f"req_{job_id}_{idx}",
                "method": "POST",
                "url": "/chat/completions",
                "body": {
                    "model": "gpt-4.1",
                    "messages": [
                        {"role": "system", "content": "あなたは有能なアシスタントです。"},
                        {"role": "user", "content": prompt}
                    ],
                    "max_tokens": 500
                }
            })
        
        connector = aiohttp.TCPConnector(limit=10)
        async with aiohttp.ClientSession(connector=connector) as session:
            # -batch endpointにリクエスト
            async with session.post(
                f"{self.base_url}/batches",
                json={"input_file_content": requests},
                headers=self.headers
            ) as response:
                if response.status == 200:
                    data = await response.json()
                    return data.get("id", job_id)
                else:
                    error = await response.text()
                    raise RuntimeError(f"Batch creation failed: {error}")

    async def get_batch_results(
        self,
        batch_id: str,
        timeout: int = 300
    ) -> list[dict]:
        """バッチジョブの結果を取得"""
        connector = aiohttp.TCPConnector(limit=5)
        start_time = asyncio.get_event_loop().time()
        
        async with aiohttp.ClientSession(connector=connector) as session:
            while True:
                async with session.get(
                    f"{self.base_url}/batches/{batch_id}",
                    headers=self.headers
                ) as response:
                    data = await response.json()
                    status = data.get("status")
                    
                    if status == "completed":
                        # 結果ファイルを取得
                        output_file_id = data.get("output_file_id")
                        return await self._fetch_results(session, output_file_id)
                    
                    elif status in ("failed", "expired", "cancelled"):
                        raise RuntimeError(f"Batch job {status}: {data.get('error')}")
                    
                    # ポーリング間隔を動的に調整
                    await asyncio.sleep(min(10, (asyncio.get_event_loop().time() - start_time) / 10))
                    
                    if asyncio.get_event_loop().time() - start_time > timeout:
                        raise TimeoutError(f"Batch job timeout after {timeout}s")

    async def _fetch_results(
        self,
        session: aiohttp.ClientSession,
        file_id: str
    ) -> list[dict]:
        """結果ファイルをダウンロードしてパース"""
        async with session.get(
            f"{self.base_url}/files/{file_id}/content",
            headers=self.headers
        ) as response:
            content = await response.text()
            return [json.loads(line) for line in content.strip().split("\n") if line]

最適なバッチサイズの決定ロジック

def calculate_optimal_batch_size( avg_prompt_tokens: int, avg_output_tokens: int, model_context_window: int = 128000 ) -> int: """ コンテキストウィンドウに基づいて最適なバッチサイズを計算 """ tokens_per_request = avg_prompt_tokens + avg_output_tokens # 安全係数(システムプロンプト、JSONフォーマットオーバーヘッド) safety_factor = 0.8 effective_window = model_context_window * safety_factor optimal_batch = max(1, int(effective_window / tokens_per_request)) # HolySheepのバッチ制限(最大50件) return min(optimal_batch, 50)

使用例

async def main(): processor = BatchProcessor(api_key="YOUR_HOLYSHEEP_API_KEY") # 1000件のプロンプトを処理 prompts = [f"質問 {i}: {生成したい内容}" for i in range(1000)] # 最適なバッチサイズを計算 batch_size = calculate_optimal_batch_size( avg_prompt_tokens=200, avg_output_tokens=300 ) print(f"最適バッチサイズ: {batch_size}") # バッチに分割して処理 batches = [prompts[i:i+batch_size] for i in range(0, len(prompts), batch_size)] all_results = [] for idx, batch in enumerate(batches): print(f"バッチ {idx+1}/{len(batches)} を処理中...") batch_id = await processor.create_batch_job(batch) results = await processor.get_batch_results(batch_id) all_results.extend(results) print(f"合計 {len(all_results)} 件の結果を取得") asyncio.run(main())

バッチ処理の強みはAPI呼び出し回数を劇的に減らせることです。HolySheep AIのbatch APIなら25%安い料金で処理できます。

3. 分散フォールトトレラントプロキシ

複数のAPIキーを異なるプロバイダーに分散させ、自動フェイルオーバー机制を構築します。

import asyncio
import aiohttp
from dataclasses import dataclass, field
from typing import Optional
from enum import Enum
import time
from collections import defaultdict

class Provider(Enum):
    HOLYSHEEP = "holysheep"
    OPENAI = "openai"  # フォールバック用
    ANTHROPIC = "anthropic"

@dataclass
class ProviderConfig:
    name: Provider
    base_url: str
    api_key: str
    rate_limit: int  # requests per minute
    current_load: int = 0
    error_count: int = 0
    last_error_time: float = 0
    latency_avg: float = 0

@dataclass
class RequestResult:
    provider: Provider
    success: bool
    data: Optional[dict] = None
    error: Optional[str] = None
    latency_ms: float = 0

class DistributedProxy:
    def __init__(self):
        self.providers: dict[Provider, ProviderConfig] = {}
        self.stats = defaultdict(lambda: {"success": 0, "failure": 0, "latencies": []})
        self._health_check_interval = 60
        self._circuit_breaker_threshold = 5
        self._circuit_breaker_cooldown = 300  # 5分

    def add_provider(
        self,
        name: Provider,
        api_key: str,
        rate_limit: int,
        base_url: Optional[str] = None
    ):
        """プロバイダーを追加(HolySheepがデフォルト)"""
        if base_url is None:
            if name == Provider.HOLYSHEEP:
                base_url = "https://api.holysheep.ai/v1"
            elif name == Provider.OPENAI:
                base_url = "https://api.openai.com/v1"
            elif name == Provider.ANTHROPIC:
                base_url = "https://api.anthropic.com/v1"
        
        self.providers[name] = ProviderConfig(
            name=name,
            base_url=base_url,
            api_key=api_key,
            rate_limit=rate_limit
        )

    def _is_provider_available(self, provider: ProviderConfig) -> bool:
        """サーキットブレーカー状態をチェック"""
        if provider.error_count >= self._circuit_breaker_threshold:
            if time.time() - provider.last_error_time < self._circuit_breaker_cooldown:
                return False
            # クーリングダウン後のリセット
            provider.error_count = 0
        return True

    def _select_provider(self) -> Optional[ProviderConfig]:
        """Least-Connections方式で最適なプロバイダーを選択"""
        available = [
            p for p in self.providers.values()
            if self._is_provider_available(p)
        ]
        
        if not available:
            return None
        
        # 最小負荷のプロバイダーを選択
        return min(available, key=lambda p: p.current_load)

    async def _call_api(
        self,
        provider: ProviderConfig,
        payload: dict
    ) -> RequestResult:
        """单个プロバイダーへのAPI呼び出し"""
        start_time = time.time()
        headers = {
            "Authorization": f"Bearer {provider.api_key}",
            "Content-Type": "application/json"
        }
        
        try:
            connector = aiohttp.TCPConnector(limit=10)
            async with aiohttp.ClientSession(connector=connector) as session:
                async with session.post(
                    f"{provider.base_url}/chat/completions",
                    json=payload,
                    headers=headers,
                    timeout=aiohttp.ClientTimeout(total=30)
                ) as response:
                    latency = (time.time() - start_time) * 1000
                    
                    if response.status == 200:
                        data = await response.json()
                        provider.latency_avg = (provider.latency_avg * 0.9 + latency * 0.1)
                        return RequestResult(
                            provider=provider.name,
                            success=True,
                            data=data,
                            latency_ms=latency
                        )
                    elif response.status == 429:
                        # レートリミット時の指数バックオフ
                        await asyncio.sleep(2 ** provider.current_load)
                        return RequestResult(
                            provider=provider.name,
                            success=False,
                            error="Rate limited"
                        )
                    else:
                        provider.error_count += 1
                        provider.last_error_time = time.time()
                        return RequestResult(
                            provider=provider.name,
                            success=False,
                            error=f"HTTP {response.status}"
                        )
        except Exception as e:
            provider.error_count += 1
            provider.last_error_time = time.time()
            return RequestResult(
                provider=provider.name,
                success=False,
                error=str(e)
            )

    async def chat_completion(
        self,
        messages: list[dict],
        model: str = "gpt-4.1"
    ) -> RequestResult:
        """分散フォールトオーバー付きでchat completionを実行"""
        payload = {
            "model": model,
            "messages": messages,
            "max_tokens": 1000
        }
        
        max_retries = len(self.providers)
        
        for attempt in range(max_retries):
            provider = self._select_provider()
            if not provider:
                return RequestResult(
                    provider=Provider.HOLYSHEEP,  # フォールバック先
                    success=False,
                    error="All providers unavailable"
                )
            
            provider.current_load += 1
            
            try:
                result = await self._call_api(provider, payload)
                
                if result.success:
                    self.stats[provider.name]["success"] += 1
                    self.stats[provider.name]["latencies"].append(result.latency_ms)
                    return result
                
                self.stats[provider.name]["failure"] += 1
                
                # 別のプロバイダーでリトライ
                if attempt < max_retries - 1:
                    await asyncio.sleep(0.5 * (attempt + 1))
                    
            finally:
                provider.current_load = max(0, provider.current_load - 1)
        
        return RequestResult(
            provider=Provider.HOLYSHEEP,
            success=False,
            error="All retry attempts failed"
        )

    def get_stats(self) -> dict:
        """現在の負荷分散統計を返す"""
        return {
            name: {
                "load": p.current_load,
                "error_count": p.error_count,
                "avg_latency_ms": round(p.latency_avg, 2),
                "success_rate": (
                    self.stats[name]["success"] / 
                    max(1, self.stats[name]["success"] + self.stats[name]["failure"])
                )
            }
            for name, p in self.providers.items()
        }

使用例

async def main(): proxy = DistributedProxy() # HolySheepを主プロバイダーとして追加 proxy.add_provider( name=Provider.HOLYSHEEP, api_key="YOUR_HOLYSHEEP_API_KEY", rate_limit=1000, # ¥1=$1のレート base_url="https://api.holysheep.ai/v1" ) # フォールバック用プロバイダー(必要に応じて) # proxy.add_provider(Provider.OPENAI, "backup-key", 500) # 100件の同時リクエストをテスト tasks = [ proxy.chat_completion( messages=[{"role": "user", "content": f"テストプロンプト {i}"}], model="gpt-4.1" ) for i in range(100) ] results = await asyncio.gather(*tasks, return_exceptions=True) successful = sum(1 for r in results if isinstance(r, RequestResult) and r.success) failed = sum(1 for r in results if isinstance(r, RequestResult) and not r.success) print(f"成功: {successful}, 失敗: {failed}") print(f"統計: {proxy.get_stats()}") asyncio.run(main())

4. プロダクショングレードの 워ーカープール

RedisやBullMQを用いたエンタープライズレベルのリクエスト管理です。

import asyncio
import aiohttp
from dataclasses import dataclass
from typing import Optional, Callable
import uuid
import json
from enum import Enum

class JobStatus(Enum):
    PENDING = "pending"
    PROCESSING = "processing"
    COMPLETED = "completed"
    FAILED = "failed"

@dataclass
class Job:
    job_id: str
    prompt: str
    status: JobStatus = JobStatus.PENDING
    result: Optional[dict] = None
    error: Optional[str] = None
    priority: int = 0
    created_at: float = 0
    started_at: Optional[float] = None
    completed_at: Optional[float] = None

注:実際の本番環境ではRedis + BullMQを使用してください

ここではデモ用のインプロセsimplementation

class InMemoryJobQueue: def __init__(self, max_concurrent: int = 10): self.max_concurrent = max_concurrent self.jobs: dict[str, Job] = {} self.pending_queue: list[str] = [] self.processing: set[str] = set() self.completed_results: dict[str, Job] = {} self._lock = asyncio.Lock() def enqueue( self, prompt: str, priority: int = 0, job_id: Optional[str] = None ) -> str: job_id = job_id or str(uuid.uuid4()) job = Job( job_id=job_id, prompt=prompt, priority=priority ) self.jobs[job_id] = job # 優先度順に挿入 inserted = False for i, qid in enumerate(self.pending_queue): if self.jobs[qid].priority < priority: self.pending_queue.insert(i, job_id) inserted = True break if not inserted: self.pending_queue.append(job_id) return job_id async def dequeue(self) -> Optional[Job]: async with self._lock: if len(self.processing) >= self.max_concurrent: return None if not self.pending_queue: return None job_id = self.pending_queue.pop(0) job = self.jobs[job_id] job.status = JobStatus.PROCESSING self.processing.add(job_id) return job async def complete(self, job_id: str, result: dict): async with self._lock: if job_id in self.processing: self.processing.remove(job_id) job = self.jobs[job_id] job.status = JobStatus.COMPLETED job.result = result self.completed_results[job_id] = job async def fail(self, job_id: str, error: str): async with self._lock: if job_id in self.processing: self.processing.remove(job_id) job = self.jobs[job_id] job.status = JobStatus.FAILED job.error = error def get_result(self, job_id: str) -> Optional[Job]: return self.completed_results.get(job_id) class WorkerPool: def __init__( self, queue: InMemoryJobQueue, api_key: str, base_url: str = "https://api.holysheep.ai/v1", num_workers: int = 5 ): self.queue = queue self.api_key = api_key self.base_url = base_url self.num_workers = num_workers self.workers: list[asyncio.Task] = [] self._running = False async def worker_loop(self, worker_id: int): """单个ワーカープロセス""" headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } connector = aiohttp.TCPConnector(limit=5) async with aiohttp.ClientSession(connector=connector) as session: while self._running: job = await self.queue.dequeue() if job is None: await asyncio.sleep(0.1) continue payload = { "model": "gpt-4.1", "messages": [ {"role": "system", "content": "簡潔かつ正確に回答してください。"}, {"role": "user", "content": job.prompt} ], "max_tokens": 800, "temperature": 0.7 } try: async with session.post( f"{self.base_url}/chat/completions", json=payload, headers=headers, timeout=aiohttp.ClientTimeout(total=45) ) as response: if response.status == 200: data = await response.json() await self.queue.complete(job.job_id, data) else: error = await response.text() await self.queue.fail( job.job_id, f"HTTP {response.status}: {error}" ) except Exception as e: await self.queue.fail(job.job_id, str(e)) async def start(self): """ワーカープールを開始""" self._running = True self.workers = [ asyncio.create_task(self.worker_loop(i)) for i in range(self.num_workers) ] async def stop(self): """ワーカープールを停止""" self._running = False await asyncio.gather(*self.workers, return_exceptions=True)

使用例

async def main(): queue = InMemoryJobQueue(max_concurrent=10) pool = WorkerPool( queue=queue, api_key="YOUR_HOLYSHEEP_API_KEY", num_workers=5 ) # ワーカープール開始 await pool.start() # 優先度付きで500件投入 print("500件のリクエストを投入中...") job_ids = [] for i in range(500): priority = 1 if i % 10 == 0 else 0 # 10%を高優先度に job_id = queue.enqueue( prompt=f"ドキュメント {i+1} の分析結果を提供してください", priority=priority ) job_ids.append(job_id) # 結果収集 completed = 0 while completed < 500: await asyncio.sleep(1) new_completed = sum( 1 for jid in job_ids if queue.get_result(jid) is not None ) if new_completed > completed: print(f"完了: {new_completed}/500") completed = new_completed await pool.stop() # サマリー success = sum( 1 for jid in job_ids if queue.get_result(jid) and queue.get_result(jid).result ) print(f"最終結果: 成功 {success}/500") asyncio.run(main())

手法比較表

手法 実装難易度 最大スループット コスト効率 耐障害性 レイテンシ 推奨シーン
リクエストキューイング ⭐ 低 接続数上限 × 1/RTT ⭐⭐ 普通 ⭐⭐⭐ 高 高(キュー待機あり) バックグラウンド処理、低優先度タスク
リクエストバッチング ⭐⭐ 中 非常に高(50件/呼) ⭐⭐⭐⭐⭐ 最高(25%割引) ⭐⭐ 中 中〜高(バッチ完了待機) オフライン処理、大量データ変換
分散フォールトトレラント ⭐⭐⭐ 中〜高 高(並列キー使用) ⭐⭐⭐⭐ 高 ⭐⭐⭐⭐⭐ 最高 低〜中 ミッションクリティカル、本番サービス
ワーカープール ⭐⭐⭐⭐ 高 高(動的スケール) ⭐⭐⭐⭐ 高 ⭐⭐⭐⭐⭐ 最高 大規模リアルタイム処理

HolySheep AI独自の優位性

HolySheep AIは同時接続数制限の突破において、他プロバイダーにない 특異なメリットを提供します:

向いている人・向いていない人

✅ 向いている人

❌ 向いていない人

価格とROI

2026年output価格の主要モデル比較:

モデル 通常価格($/MTok) HolySheep価格($/MTok) 節約率 月間1万ドルの場合
GPT-4.1 $60.00 $8.00 87%OFF $133/月相当
Claude Sonnet 4.5 $135.00 $15.00 89%OFF $111/月相当
Gemini 2.5 Flash $7.50 $2.50 67%OFF $333/月相当
DeepSeek V3.2 $1.10 $0.42 62%OFF $2,381/月相当

私の实践经验では、同時接続数制限の突破とHolySheepの組み合わせにより、従来の方法相比で年間500万円以上のコスト削減を実現したプロジェクトもあります。特にバッチ処理を活用するオフライン分析ワークロードでは、元のコスト比80%减達成は珍しくないです。

HolySheepを選ぶ理由

同時接続数制限の解決策としてHolySheep AIを選択すべき理由は明白です:

  1. 85%のコスト削減:¥1=$1の汇率は他の追随を許さない
  2. ネイティブ的人民元決済:WeChat Pay/Alipayで気軽にチャージ可能
  3. <50msの応答速度:アジアからのアクセスに最適
  4. batch APIの25%割引:大批量処理をさらに効率化
  5. 無料クレジット付き登録:リスクなく試用可能

複数の同時接続数制限突破手法を組み合わせることも可能ですが、ベースプロバイダーとしてHolySheepを採用すれば、シンプルさとコスト効率を同時に最大化できます。

よくあるエラーと対処法

エラー1:429 Too Many Requests

# 症状:API呼び出し時に429エラーが频発する

原因:同時接続数またはレート制限を超過

対処法:指数バックオフ+リクエスト間隔の制御

import asyncio import aiohttp async def call_with_retry( url: str, headers: dict, payload: dict, max_retries: int = 5, base_delay: float = 1.0 ): for attempt in range(max_retries): connector = aiohttp.TCPConnector(limit=10) async with aiohttp.ClientSession(connector=connector) as session: try: async with session.post( url, json=payload, headers=headers, timeout=aiohttp.ClientTimeout(total=30) ) as response: if response.status == 200: return await response.json() elif response.status == 429: # 指数バックオフ:2^attempt秒待機 delay = base_delay * (2 ** attempt) print(f"Rate limit hit. Waiting {delay}s...") await asyncio.sleep(delay) else: raise aiohttp.ClientError(f"HTTP {response.status}") except Exception as e: if attempt == max_retries - 1: raise await asyncio.sleep(base_delay * (2 ** attempt)) raise RuntimeError("Max retries exceeded")

エラー2:Connection Pool Exhausted

# 症状:aiohttp.ClientError: Pool limit reached

原因:TCPConnectorの接続プール上限に達している

対処法:プールサイズの適切な設定+接続の再利用

import a