Tablo API
← Все статьи
24 июля 2026 г.

Реалтайм данные о рейсах: архитектура для высоконагруженных сервисов

Если через ваш сервис проходят тысячи проверок статусов рейсов в день (турагрегатор, страховая, такси-сервис), наивный polling быстро упирается в лимиты API и создаёт лишнюю нагрузку. Разбираем архитектуру, которая выдерживает масштаб.

Проблема: лишние запросы

Tablo API ограничивает запросы скользящим окном — 100 запросов за 10 минут на один ключ. При превышении — 429 Too Many Requests с заголовком Retry-After. Если опрашивать API за каждым рейсом отдельно, лимит выбьет вас на первом же пиковом дне.

Слой 1: кэш по data_freshness

Каждый ответ содержит data_freshness — время последнего обновления данных по аэропорту:

{
  "data_freshness": { "SVO": "2026-07-24T10:25:00.000Z" }
}

Данные обновляются раз в 15 минут. Нет смысла запрашивать чаще — кэшируйте ответ до следующего обновления:

import time
import requests

CACHE: dict[str, tuple[float, dict]] = {}
TTL_SECONDS = 15 * 60

def get_flights(airport: str, flight_type: str, date: str) -> dict:
    key = f"{airport}:{flight_type}:{date}"
    cached = CACHE.get(key)
    if cached and time.time() - cached[0] < TTL_SECONDS:
        return cached[1]

    response = requests.get(
        "https://api.tabloapi.ru/v1/flights",
        headers={"X-API-Key": "YOUR_KEY"},
        params={"airport": airport, "type": flight_type, "date": date},
    )
    response.raise_for_status()
    data = response.json()
    CACHE[key] = (time.time(), data)
    return data

Слой 2: вебхуки вместо циклического опроса

Для конкретных рейсов, которые нужно отслеживать точечно (а не весь поток по аэропорту), замените polling на вебхук — подробности в статье «Как подключить вебхуки для мониторинга задержек рейсов». Это снимает нагрузку и с вашей стороны, и с лимита API.

Слой 3: идемпотентная обработка событий

При высоком трафике вебхуков и ретраях на вашей стороне важно не обработать одно и то же событие дважды. Используйте комбинацию flight_number + field + changed_at как ключ идемпотентности:

const processedEvents = new Set(); // в проде — Redis SET с TTL

function handleWebhookEvent(event) {
  const eventKey = `${event.flight_number}:${event.field}:${event.changed_at}`;
  if (processedEvents.has(eventKey)) {
    return; // уже обработано, пропускаем
  }
  processedEvents.add(eventKey);

  // бизнес-логика: уведомление пассажира, пересчёт компенсации и т.д.
}

Слой 4: backoff при 429

Даже с кэшем и вебхуками возможны всплески. Реализуйте экспоненциальный backoff:

import time

def request_with_backoff(fn, max_retries=5):
    delay = 1
    for attempt in range(max_retries):
        response = fn()
        if response.status_code != 429:
            return response
        retry_after = int(response.headers.get("Retry-After", delay))
        time.sleep(retry_after)
        delay *= 2
    raise RuntimeError("Rate limit exceeded after max retries")

Итоговая схема

  1. Кэш по data_freshness — не более одного запроса на аэропорт за 15 минут
  2. Вебхуки — для точечного отслеживания конкретных рейсов
  3. Идемпотентность — по flight_number + field + changed_at
  4. Backoff — на случай пиковой нагрузки

Такая архитектура выдерживает нагрузку без превышения лимитов и лишних затрат на инфраструктуру.


Запросить доступ к API → · Документация →