Привет! Я хочу показать, что запуск gRPC в PHP — это обычное боевое решение, которое быстро пишется, легко развертывается и может оказаться для вас проще, чем сокеты.
Поначалу в REST всё работало и работало хорошо, но начался рост.
Skyeng постоянно взаимодействует со студентами: периодически нам нужно звонить — чтобы подтвердить запись на пробный урок или, например, уточнить, все ли в порядке, если человек пропустил урок.На заре школы работа со звонками велась вручную, но бизнесу быстро захотелось как-то автоматизировать и анализировать работу операторов.
Voximplant помог сделать это.
Мы до сих пор пользуемся их технологией – это удобно.
Чтобы операторы не слушали гудки, не тратили время на набор недоступных номеров и так далее, у ребят есть PDS (система предиктивного набора) - система автоматического набора номера.
Он принимает два пула — операторов и клиентов и по ходу звонка вычисляет контактный номер базы данных, задавая скорость дальнейшего дозвона.
Идея состоит в том, чтобы операторы и клиенты как можно меньше ждали на линии.
Долгое время все работало примерно по такой схеме.
Например, мы загружаем список PDS из 1000 номеров — и знаем, что у нас теперь 50 операторов.
Начинаем обзванивать первые 100.
- Номер недоступен — обрабатываем скрипт на JS, отправляем номер и его статус на конечную точку, записываем факт неудачного звонка в базу данных.
- Срабатывает автоответчик: все то же самое, но со статусом «автоответчик».
- Совершается звонок клиенту – он берет трубку и говорит «Здравствуйте».
В это время из пула операторов срочно ищется первый подходящий: мы знаем, что если держать человека «на линии» более двух секунд, он просто повесит трубку.
PDS вычисляет контактную информацию из базы данных и набирает еще несколько номеров.
При этом он подсчитывает продолжительность текущих разговоров и обновляет статистику, чтобы сбалансировать время ожидания операторов и клиентов.
Упор всегда делается на удобство клиента (те самые пару секунд), но время простоя оператора не должно затягиваться.
Это нормально, если это 30-40 секунд. На практике так сложилось, что загрузка времени операторов доходила почти до 30% — долго сидели в ожидании, это было критично.
Также мы стали сталкиваться со случаями двойного звонка.
Утром мы собрали большой список звонков на тысячи номеров и загрузили его в систему.
Но в то же время через сайт приходили новые потенциальные студенты — опять же, бизнес на опыте установил, что их следует вызывать в приоритете в течение следующих нескольких часов после подачи заявки.
В PDS не было опции «добавить номера».
Поэтому мы остановили его, обновили таблицу и запустили снова.
Но на момент остановки часть номеров могла быть набрана, но их статусы еще не поступили в базу данных.
Они не были помечены как набранные и случалось, что мы разговаривали с человеком, а через две минуты ему набирал номер следующий оператор.
Мы не могли отметить, что номер дан для набора на нашей стороне: так как мы работали с тысячами количества одновременно, это вызвало большие задержки на нашей базе.
Тогда ребята из Voximplant предоставили нам прототип своего нового PDS — более совершенного решения под названием PDS2. И нам нужно было как-то к этому подключиться.
Почему стоит выбрать gRPC? И почему не работал клиент Go?
О, у gRPC есть много интересных функций:- Protobuf как инструмент описания сериализации типов данных — протокол описываем в протофайле, это быстро.
syntax = "proto3" ; message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3 }
- Есть плагин gRPC, который позволяет сгенерировать из протофайла весь необходимый код — сервис, типы, PDS-клиент, в нашем случае.
Единственное, что он не генерирует — это серверную часть на PHP.
- HTTP/2 как транспорт — можно прекратить выполнение запроса на сервере, а также повторно использовать один сокет для нескольких параллельных запросов.
- Вместо ввода «domain.com/service/collection/resource/query? параметр=значение», как и в REST, здесь есть только сервис.
Все остальное описывается через Protobuf с точки зрения нашей модели и ее событий.
Однако их выбрали не из-за особенностей: выбора просто не было — PDS2 общался только через gRPC.
Но мы попробовали это с Go. Прототип клиента от разработчиков из Voximplant некоторое время находился в производстве, но его было сложно поддерживать.PHP — основной язык Skyeng; там почти все написано.
И мы поняли, что нужно перетащить много кода в клиент Go, а затем поддерживать его и в клиенте, и в PHP-части.
Например, у нас были проблемы с часовыми поясами — и решение было, но на PHP. И все это нужно было перенести в тот Go-клиент. Мы долго обсуждали это с тимлидом и в итоге решили, что проще будет всё сделать на PHP. После месяцев использования понимаю, что это было правильное решение.
Что делать, если PHP не был доставлен? Написать решение (почти) легко
Я выполнил рекомендации от gRPC.io для PHP. В принципе, там описано все, что вам нужно.Был только один забавный нюанс.
Пару дней я искал решение, как генерировать код с пространствами имен в нашем протофайле.
Я все сгенерировал, все хорошо, но их мало.
В итоге я сел перечитывать всю документацию.
Оказалось, это называется пакеты.
Итак, если вы тоже задаетесь вопросом, то все довольно просто: пишем в файл package foo.bar;
message MyMessage {}
И это создаст такое пространство имен.
Foo\Bar\MyMessage
Подробности по связь .
Как это работает. При генерации задаем необходимые параметры для подключения к Voximplant, запускаем и получаем бесконечный цикл, который постоянно слушает наш поток.
Наш клиент, по сути, обычный демон.
Здесь пример от Воксимплант. Нашу связку показать вам не могу: она сильно разрослась из-за сложной и специфической для нас логики.
Каков результат?
Наш клиент совместно с супервайзером работает на продакшене с января, всё стабильно.В сочетании с супервизором это почти демон - если что случится, супервайзер подхватит и зафиксирует падение себе.
Мы решили растущие проблемы.
Благодаря демону мы отправляем номера по запросу, динамически, небольшими порциями — по 50 за раз.
И теперь, если у нас есть какие-то «горячие» номера с сайта, он уже знает, что эти номера имеют высший приоритет — когда приходит новый запрос от Voximplamt, он их отправляет. Теперь у нас есть гибкость.
Также время ожидания операторов сократилось примерно до 20 секунд, но это исключительно за счет лучших алгоритмов самого PDS2, которые мы не писали.
Теги: #api #разработка сайтов #php #grpc #symfony
-
Мендель, Грегор Иоанн
19 Oct, 24 -
Тиан
19 Oct, 24 -
Умный Дом На Колесах... Без Яндекса?
19 Oct, 24 -
Невидимая Революция
19 Oct, 24 -
Рецепты Для Android: Ioc Со Вкусом Gradle
19 Oct, 24