Весной 2012 года по рекомендациям наших постоянных клиентов к нам обратился молодой, амбициозный и напористый бизнесмен из Москвы с заказом, который привел нас в ступор… И хотя на тот момент мы работали на рынке Друпал-разработки около 5 лет, однако таких сложных задач перед нами еще не ставили. Проект назывался HiConversion и предполагал следующий функционал:
- публикация и управление рекламными объявлениями в соц сети VK;
- сбор статистики по всем опубликованным объявлениям с внешних источников, таких как VK, Google Analytics, Yandex.Metrica;
- возможность просмотра статистики по опубликованным объявлениям за любой период времени;
- автоматическое или ручное управление объявлениями в зависимости от результатов собранной статистики;
- возможность настраивать все таргетинги, как в индивидуальном порядке, так и массово;
- средства для работы рекламных агентств, иерархическая система ролей и доступов;
- контроль состояния счета клиента: возможность его пополнения, автоматическая остановка объявлений.
И это далеко не исчерпывающий список. Но давайте рассмотрим архитектурный подход к реализации такого технически сложного проекта более подробно.
Как вы видите, поставленные перед проектом задачи были далеко не тривиальными для веб-приложения, тем более, они полностью выходили за рамки “родного” для Drupal функционала. Необходимость обновлять десятки тысяч запросов в минуту информацией с внешних источников заставила нас искать нетрадиционные решения для преодоления ограничений большинства механизмов как ядра Drupal, так и сторонних сервисов.
Для наиболее эффективного использования ограничений сторонних сервисов на запросы, учитывая разный формат данных, их принципов коммуникации и аутентификации, нам довелось переосмыслить формат сохранения и обработки очередей в Drupal. Очередь обрабатывалась не благодаря медленным запросам по расписанию (cron), а php-демоном, который постоянно мониторил наличие элементов в очереди и выполнял задачи настолько быстро, насколько это вообще было возможно. За лимитами ресурсов вела наблюдение сложная система “семафоров”, построенная на основе механизмов замков Drupal (Lock API), а созданные нами интерфейсы позволяли удобно и юзабильно добавлять новые типы элементов очереди.
Поскольку нам приходилось сохранять огромнейшие объемы статистических данных (около миллиона записей) и постоянно их обновлять, мы были вынуждены глубоко модифицировать принцип обработки полей в Drupal. Для того, чтобы совершенно не уйти от философии Drupal и иметь возможность использовать максимальное количество стандартных решений, мы не только создали новые, более приспособленные к нашим условиям типы полей, но и использовали возможности Drupal Field Storage API на все 100%. Большинство операций в нашем случае требовали обновления большого количества полей однотипной информацией за один раз, поэтому мы значительно выиграли в продуктивности, добавив возможность массового обновления полей с последующим вызовом необходимых хуков. Такой подход позже позволил нам использовать готовые модули для построения сложных представлений (views) с запутанными наборами фильтров и возможностью их сохранения.
Невзирая на всю сложность построенной нами системы, мы также заложили в ее фундамент возможность расширения функционала и добавления обработчиков событий очереди с гибкими настройками. В юзер-интерфейсе это выглядело как добавление нового элемента Field Collection с набором полей настроек, а со стороны кода необходимо было лишь добавить обработчик этих настроек и правил реакции на события, расширив базовый класс поведения (reaction handler-a).