Itinai.com mockup of branding agency website on laptop. moder 03f172b9 e6d0 45d8 b393 c8a3107c17e2 0

Создание производительного асинхронного Python SDK с ограничением скорости и кэшированием

Itinai.com mockup of branding agency website on laptop. moder 03f172b9 e6d0 45d8 b393 c8a3107c17e2 0

Руководство по созданию готового к производству асинхронного Python SDK с ограничением скорости, кэшированием в памяти и аутентификацией

Создание надежного и производительного SDK для работы с API — задача, требующая внимания к деталям и понимания современных технологий. В этом руководстве мы рассмотрим, как разработать асинхронный Python SDK, который будет включать в себя такие важные компоненты, как ограничение скорости, кэширование в памяти и аутентификация. Мы будем использовать библиотеки aiohttp и nest-asyncio, чтобы обеспечить эффективное выполнение HTTP-запросов.

Установка и настройка

Первым шагом будет установка необходимых библиотек. Выполните следующую команду:

!pip install aiohttp nest-asyncio

Эта команда установит асинхронные библиотеки, которые позволят нам работать с HTTP-запросами и управлять потоками событий.

Реализация основных компонентов

Структурированный объект ответа

Для начала создадим класс APIResponse, который будет хранить детали ответа от API:

from dataclasses import dataclass
from typing import Any, Dict
from datetime import datetime

@dataclass
class APIResponse:
    data: Any
    status_code: int
    headers: Dict[str, str]
    timestamp: datetime

    def to_dict(self) -> Dict:
        return asdict(self)

Этот класс инкапсулирует информацию о HTTP-ответе, включая полезную нагрузку, код состояния и заголовки.

Ограничение скорости

Следующий шаг — реализация механизма ограничения скорости. Мы создадим класс RateLimiter, который будет управлять количеством запросов:

import time

class RateLimiter:
    def __init__(self, max_calls: int = 100, time_window: int = 60):
        self.max_calls = max_calls
        self.time_window = time_window
        self.calls = []

    def can_proceed(self) -> bool:
        now = time.time()
        self.calls = [call_time for call_time in self.calls if now - call_time < self.time_window]
        if len(self.calls) < self.max_calls:
            self.calls.append(now)
            return True
        return False

    def wait_time(self) -> float:
        if not self.calls:
            return 0
        return max(0, self.time_window - (time.time() - self.calls[0]))

Класс RateLimiter реализует политику токенов, позволяя контролировать количество запросов к API.

Кэширование в памяти

Теперь добавим кэширование для повышения производительности. Создадим класс Cache, который будет хранить ответы:

from datetime import timedelta
import hashlib
import json

class Cache:
    def __init__(self, default_ttl: int = 300):
        self.cache = {}
        self.default_ttl = default_ttl

    def _generate_key(self, method: str, url: str, params: Dict = None) -> str:
        key_data = f"{method}:{url}:{json.dumps(params or {}, sort_keys=True)}"
        return hashlib.md5(key_data.encode()).hexdigest()

    def get(self, method: str, url: str, params: Dict = None) -> Optional[APIResponse]:
        key = self._generate_key(method, url, params)
        if key in self.cache:
            response, expiry = self.cache[key]
            if datetime.now() < expiry:
                return response
            del self.cache[key]
        return None

    def set(self, method: str, url: str, response: APIResponse, params: Dict = None, ttl: int = None):
        key = self._generate_key(method, url, params)
        expiry = datetime.now() + timedelta(seconds=ttl or self.default_ttl)
        self.cache[key] = (response, expiry)

Класс Cache предоставляет легковесное кэширование с ограничением по времени жизни (TTL) для ответов API.

Расширенный класс SDK

Теперь объединим все компоненты в класс AdvancedSDK, который будет управлять сессиями и аутентификацией:

import aiohttp
import logging

class AdvancedSDK:
    def __init__(self, base_url: str, api_key: str = None, rate_limit: int = 100):
        self.base_url = base_url.rstrip('/')
        self.api_key = api_key
        self.session = None
        self.rate_limiter = RateLimiter(max_calls=rate_limit)
        self.cache = Cache()
        self.logger = self._setup_logger()

    def _setup_logger(self) -> logging.Logger:
        logger = logging.getLogger(f"SDK-{id(self)}")
        if not logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
            handler.setFormatter(formatter)
            logger.addHandler(handler)
            logger.setLevel(logging.INFO)
        return logger

    async def __aenter__(self):
        self.session = aiohttp.ClientSession()
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        if self.session:
            await self.session.close()

Класс AdvancedSDK интегрирует все компоненты, управляя сессиями и заголовками, а также координируя ограничение скорости и кэширование.

Демонстрация возможностей SDK

Теперь давайте посмотрим, как использовать наш SDK:

async def demo_sdk():
    async with AdvancedSDK("https://jsonplaceholder.typicode.com") as sdk:
        response = await sdk.get("/posts/1")
        print(f"Status: {response.status_code}, Title: {response.data.get('title', 'N/A')}")

Функция demo_sdk демонстрирует основные функции SDK, выполняя GET-запросы и показывая кэширование и обработку ошибок.

Заключение

Это руководство по созданию SDK предоставляет масштабируемую основу для любой интеграции RESTful, сочетая современные практики программирования на Python с практическими инструментами. Применяя описанные паттерны, команды разработчиков могут ускорить создание новых клиентов API, обеспечивая предсказуемость, наблюдаемость и устойчивость.

Для получения дополнительных ресурсов и обсуждений в сообществе, пожалуйста, следите за нами в Twitter и присоединяйтесь к нашему сабреддиту по машинному обучению.

Новости в сфере искусственного интеллекта