Реализуйте rate limiter для обработчика: у каждого клиента есть client_id, limit и interval; нужно ограничить число вызовов handler для каждого клиента в скользящем временном окне и выбрасывать RateLimitExceededError.

Для точного скользящего окна храните очередь времён допущенных вызовов по clientid. Перед новым вызовом удалите события старше окна и сравните оставшееся количество с limit.

Короткий ответ

Что ответить на собеседовании

Для точного скользящего окна храните очередь времён допущенных вызовов по clientid. Перед новым вызовом удалите события старше окна и сравните оставшееся количество с limit.

Подробный разбор

Ответ с пояснениями

Для точного скользящего окна храните очередь времён допущенных вызовов по client_id. Перед новым вызовом удалите события старше окна и сравните оставшееся количество с limit.

Пример для одного процесса и одного asyncio event loop. limit и interval задаются при создании лимитера и не меняются между вызовами:

import time
from collections import defaultdict, deque

class RateLimitExceededError(Exception):
    pass

class RateLimiter:
    def __init__(self, limit, interval):
        if not isinstance(limit, int) or limit < 1 or interval <= 0:
            raise ValueError('Invalid rate limit')
        self.limit = limit
        self.interval = interval
        self.calls = defaultdict(deque)

    async def call(self, client_id, handler, *args, **kwargs):
        now = time.monotonic()
        calls = self.calls[client_id]
        cutoff = now - self.interval
        while calls and calls[0] <= cutoff:
            calls.popleft()
        if len(calls) >= self.limit:
            raise RateLimitExceededError(client_id)
        calls.append(now)
        return await handler(*args, **kwargs)

Проверка и резервирование не содержат await и в этой модели не перемежаются с другими корутинами. Считаются допущенные попытки, даже если handler завершился ошибкой. Для нескольких процессов нужен общий атомарный счётчик или хранилище; для долгой работы также нужна очистка состояния неактивных клиентов. Граница окна здесь — (now − interval, now].

Практика в реальном времени

Подготовьтесь к следующему собеседованию

Interview Boost учитывает вакансию, резюме и технологии и помогает сформулировать ответ прямо во время интервью.

Начать подготовку