КонтекстContext
Travel-продукту нужны не отдельные выгрузки, а собственная рабочая база: экскурсии, гиды, города, расписания и отзывы должны быть связаны между собой и регулярно обновляться. Эти данные используются в витринах, фильтрах, аналитике и внутренних процессах.A travel product needs more than one-off exports. It needs its own working database where experiences, guides, cities, schedules and reviews are connected and refreshed regularly. This data feeds storefronts, filters, analytics and internal workflows.
Полная перезагрузка при каждом обновлении создаёт тысячи лишних запросов, увеличивает время синхронизации и быстрее упирается в ограничения партнёрского API. При этом сбой на одном типе данных не должен заставлять начинать весь процесс заново.Running a full reload for every update creates thousands of unnecessary requests, extends sync time and reaches partner API limits sooner. A failure in one data type should not force the entire process to restart.
Бизнес-задачаBusiness task
Нужно было построить управляемый сервис автоматического сбора и актуализации данных Tripster в PostgreSQL. Он должен поддерживать большой объём записей, продолжать работу после частичных сбоев и показывать, какие данные ещё ждут обновления.The task was to build a manageable service for automatically collecting and refreshing Tripster data in PostgreSQL. It needed to handle a large record set, recover from partial failures and show which data still awaited refresh.
- Первично собрать связанные справочники и контент.Initially collect connected reference data and content.
- Обновлять только изменившиеся сущности.Refresh only changed entities.
- Не терять задачи при ограничениях API и остановках.Keep tasks through API limits and interruptions.
- Контролировать расхождения между источником и базой.Control drift between the source and database.
- Оставить критические решения и live-запуски человеку.Keep critical decisions and live runs under human control.
Что было реализованоWhat was built
Создан Python CLI-сервис, который получает данные из партнёрского API, валидирует ответы через Pydantic, нормализует различающиеся форматы и сохраняет сущности в PostgreSQL через SQLAlchemy. Отдельные команды покрывают первичную загрузку, инкрементальные обновления, обработку очереди, проверку расхождений и обновление расписаний.A Python CLI service was built to retrieve partner API data, validate responses with Pydantic, normalise differing formats and persist entities to PostgreSQL through SQLAlchemy. Separate commands cover initial loading, incremental updates, backlog processing, drift checks and schedule refreshes.
Основной рабочий режим — не повторная полная выгрузка, а инкрементальный цикл. Сервис хранит курсоры, находит изменившиеся экскурсии и ставит связанные расписания и отзывы в устойчивую очередь. Reconcile-проход проверяет лёгкие списочные данные и добавляет в очередь то, что могло разойтись.The primary operating mode is an incremental cycle rather than repeated full exports. The service stores cursors, finds changed experiences and places related schedules and reviews in a persistent backlog. A reconciliation pass checks lightweight list data and queues records that may have drifted.
- Страны, города, гиды, экскурсии, расписания и отзывы в связанной схеме.Countries, cities, guides, experiences, schedules and reviews in a connected schema.
- Full, incremental, reconcile и backlog-команды для разных режимов работы.Full, incremental, reconcile and backlog commands for distinct operating modes.
- Курсоры обновления и журнал запусков.Update cursors and run history.
- Повторяемые upsert-операции вместо дублирования записей.Repeatable upserts instead of duplicate records.
- Равномерный темп запросов, обработка 429 и пауза перед продолжением.Even request pacing, 429 handling and cooldown before continuing.
- Проверка целостности и ограниченные live-аудиты перед рабочими запусками.Integrity checks and limited live audits before working runs.
Как решения помогают бизнесуHow the decisions help the business
| РешениеDecision | ЗадачаProblem | ПользаBusiness value |
|---|---|---|
| Инкрементальная синхронизацияIncremental synchronisation | Не повторяет полную выгрузку ради небольших изменений.Avoids a full export for small changes. | Меньше запросов и короче регулярный цикл обновления.Fewer requests and a shorter routine refresh cycle. |
| Курсоры по типам данныхPer-entity cursors | Фиксируют подтверждённую точку продолжения.Record the confirmed continuation point. | Следующий запуск продолжает работу с понятного состояния.The next run resumes from a known state. |
| Устойчивая backlog-очередьPersistent backlog | Сохраняет связанные задачи на расписания и отзывы.Keeps related schedule and review tasks. | Большой объём обрабатывается управляемыми пакетами.Large volumes are processed in manageable batches. |
| Reconcile-проверкаReconciliation checks | Находит расхождения без массовых detail-запросов.Finds drift without mass detail requests. | База актуализируется экономнее и предсказуемее.The database is refreshed more economically and predictably. |
| Валидация и нормализацияValidation and normalisation | Приводит разные ответы API к устойчивой модели.Turns varying API responses into a stable model. | Ошибки формата обнаруживаются до записи в рабочие таблицы.Format issues are caught before reaching working tables. |
| Идемпотентные upsert-операцииIdempotent upserts | Обновляют существующие записи по стабильным ключам.Update existing records by stable keys. | Повторный запуск не размножает сущности.Repeated runs do not multiply entities. |
| Контроль темпа и 429Pacing and 429 control | Не допускает резких всплесков запросов и корректно реагирует на лимиты.Prevents request bursts and responds correctly to limits. | Синхронизация бережнее работает с партнёрским API.Synchronisation is gentler on the partner API. |
| Human-in-the-Loop процессHuman-in-the-Loop process | Отделяет AI-генерацию от решений с операционным риском.Separates AI generation from operational-risk decisions. | Архитектура, live-аудиты и рабочие запуски проходят человеческую проверку.Architecture, live audits and working runs receive human review. |
Почему выбрана такая архитектураWhy this architecture
Контур актуализации travel-данныхTravel data refresh flow
Автоматика поддерживает рабочую базу, а человек контролирует архитектуру, live-проверки и запуск изменений.Automation maintains the working database while a person controls architecture, live checks and change approval.
- Партнёрский APIPartner API
- Проверка и нормализацияValidation and normalisation
- PostgreSQLPostgreSQL
- Incremental, backlog и reconcileIncremental, backlog and reconcile
- Актуальная рабочая базаCurrent working database
- Human-in-the-Loop контрольHuman-in-the-Loop control
Полная синхронизация — стартовый и аварийный режимFull sync is an initial and recovery mode
Полный проход нужен для первичного наполнения или контролируемого восстановления. Регулярная актуализация строится на incremental, backlog и reconcile, чтобы не создавать тысячи повторных запросов.A full pass is used for initial population or controlled recovery. Routine refreshes rely on incremental, backlog and reconciliation so thousands of repeated requests are avoided.
Очередь отделяет обнаружение изменений от тяжёлых обновленийThe backlog separates change detection from heavy refreshes
Изменившаяся экскурсия быстро попадает в базу, а связанные расписания и отзывы обновляются пакетами. Размер пакета можно согласовать с доступным окном и лимитами API.A changed experience reaches the database quickly, while related schedules and reviews refresh in batches. Batch size can match the available operating window and API limits.
Reconcile закрывает разрывы между курсорами и источникомReconciliation closes gaps between cursors and source data
Лёгкий списочный проход сравнивает состояние источника с базой и ставит отличающиеся записи в очередь. Это страховка от пропущенных изменений без постоянной полной выгрузки.A lightweight list pass compares source and database state and queues differing records. This protects against missed changes without requiring constant full exports.
Ограничения источника учитываются явноSource limitations are handled explicitly
Live-аудит показал, что фильтр обновления для справочника гидов нельзя считать надёжным. Поэтому сервис не обещает ложный incremental для этого раздела: режим его обновления выбирается отдельно и проверяется контролируемыми запусками.A live audit showed that the guide update filter could not be treated as reliable. The service therefore makes no false incremental promise for that section; its refresh mode is selected separately and verified through controlled runs.
AI создаёт, человек отвечает за выпуск измененийAI creates; a person is accountable for releasing changes
Весь код и документация проекта сгенерированы AI. Human-in-the-Loop оставляет ответственность у человека: он формулирует требования, проверяет архитектуру и код, запускает ограниченные live-аудиты, разбирает инциденты и подтверждает изменения перед рабочими синхронизациями.All project code and documentation were generated by AI. Human-in-the-Loop keeps responsibility with a person: they define requirements, review architecture and code, run limited live audits, analyse incidents and approve changes before working synchronisations.
РезультатResult
В рабочей базе собрано 30 503 экскурсии, 8 516 гидов, 30 189 расписаний и 953 868 отзывов. Дополнительно связаны 123 страны и 937 городов. Это не демонстрационная выборка, а объём, на котором проверялись схема, upsert-операции и процесс обновления.The working database contains 30 503 experiences, 8 516 guides, 30 189 schedules and 953 868 reviews. It also connects 123 countries and 937 cities. This is not a demonstration sample: it is the volume used to verify the schema, upserts and refresh process.
Регулярный процесс обновляет изменившиеся экскурсии, сохраняет связанные задачи в backlog и отдельными пакетами актуализирует расписания и отзывы. Reconcile помогает обнаружить расхождения, а журнал запусков и курсоры делают состояние процесса проверяемым.The routine process refreshes changed experiences, stores related work in the backlog and updates schedules and reviews in separate batches. Reconciliation helps detect drift, while run history and cursors make process state inspectable.
Актуальность зависит от расписания запусков и скорости обработки backlog — это не обещание real-time. Часть редко используемых полей сохраняется в raw_data, а изменения схемы сейчас выполняются через ensure_schema, без Alembic-миграций. Эти ограничения зафиксированы и учитываются при эксплуатации.Freshness depends on run scheduling and backlog throughput; this is not a real-time promise. Some rarely used fields remain in raw_data, and schema changes currently use ensure_schema rather than Alembic migrations. These limitations are documented and considered in operation.
Где это применимоWhere it applies
Подход подходит продуктам, которым нужен собственный актуализируемый слой данных поверх внешнего каталога.The approach suits products that need their own refreshable data layer over an external catalogue.
- Туристические витрины и каталоги экскурсий.Travel storefronts and experience catalogues.
- Агрегаторы предложений из нескольких источников.Aggregators combining offers from multiple sources.
- Региональные и тематические travel-проекты.Regional and thematic travel products.
- Внутренняя аналитика контента, гидов и отзывов.Internal analytics for content, guides and reviews.
- Подготовка данных для поиска и рекомендаций.Data preparation for search and recommendations.
- Интеграционные слои для CRM и back-office систем.Integration layers for CRM and back-office systems.
ВыводConclusion
Главный результат проекта — не разовая выгрузка, а управляемая актуализация большого travel-каталога. Инкрементальные проходы, backlog и reconcile снижают нагрузку на источник и позволяют видеть незавершённую работу.The main outcome is not a one-off export but a manageable refresh process for a large travel catalogue. Incremental passes, backlog processing and reconciliation reduce source load and expose unfinished work.
AI ускорил создание всего кода и документации, но не получил право самостоятельно принимать рискованные решения. Human-in-the-Loop связал скорость генерации с инженерной проверкой и ответственным запуском.AI accelerated creation of all code and documentation but was not allowed to make risky decisions independently. Human-in-the-Loop combined generation speed with engineering review and accountable operation.