Как связать Asterisk с CRM и не отдать ей лишнее
Для карточки клиента и журнала звонков обычно достаточно AMI: CRM получает события, а вызовом продолжает управлять диалплан Asterisk. ARI выбирайте, когда приложению нужно вести сценарий звонка через Stasis. Покажу, где проходят границы этих интерфейсов, какие права выдать и что предусмотреть при сбое.
Почему карточка клиента открывается через раз
Типичная картина: менеджер снимает трубку, а карточка клиента в CRM появляется через десять секунд, или не появляется вовсе, или открывается у соседа. Подрядчик когда-то написал скрипт на PHP, который держит соединение с Asterisk, ловит события и передаёт их через интеграцию телефонии в CRM. Для второй половины связки у CRM должен быть доступный API: одного AMI недостаточно, если карточки и журнал некуда отправлять. Пока скрипт жив и Asterisk не перезапускался, всё работает. Потом обновление, перезагрузка сервера, кратковременный обрыв сети — и скрипт либо висит на мёртвом сокете, либо молча упал, а заметили это через три дня по жалобам продаж. Знакомо?
Проблема почти никогда не в самом интерфейсе Asterisk. Проблема в том, что связку писали как демонстрацию, а не как сервис: нет переподключения, нет проверки живости соединения, нет журнала полученных событий, нет понимания, какое событие считать началом разговора. Добавьте к этому выбор интерфейса «потому что ARI современнее» или «потому что про AMI есть пример на форуме» — и вы получаете хрупкую конструкцию, которую боятся трогать. Код при этом может быть вполне аккуратным: дело не в стиле, а в том, что никто не задал вопрос «а что будет, когда соединение порвётся».
Поэтому в этой статье порядок обратный привычному. Сначала решаем, какой контроль над звонком нужен CRM на самом деле. Потом выбираем интерфейс под эту задачу. И только потом пишем код — с переподключением, журналом и сверкой, иначе через полгода вы снова будете читать эту статью. В статье где хранятся записи Asterisk мы разбирали сами файлы; здесь речь о событиях и связи с CRM. Порядок скучный, зато работает. Иначе вы снова чините то же самое.
AMI: события и действия для CRM
Asterisk Manager Interface — текстовый протокол поверх TCP, по умолчанию порт 5038. Клиент подключается, проходит Login, и дальше получает поток событий о том, что происходит на станции: появление канала, смена его состояния, начало набора, соединение, завершение. В обратную сторону он может отправлять действия: Originate для исходящего вызова по клику из CRM, Hangup, Redirect, запросы статуса. Пользователи настраиваются в manager.conf: для них задают пароль, адреса permit/deny и права read и write. read разрешает получать классы событий, write — выполнять классы действий. Это разные полномочия; смешивать их в один «доступ к AMI» удобно только до первой проверки безопасности.
Для типичной CRM в офисе этого хватает с запасом. Всплывающая карточка — это реакция на событие о входящем вызове на номер менеджера. Журнал звонков — это события начала и конца с длительностью и ссылкой на запись. Звонок по клику — действие Originate. Ни одна из этих задач не требует, чтобы приложение управляло самим каналом: Asterisk ведёт звонок по своему диалплану, а CRM только наблюдает и изредка просит что-то сделать. Чем меньше ответственности у интеграции, тем спокойнее живёт отдел продаж: упал скрипт — звонки всё равно идут людям, просто без подсказки на экране.
Нюанс, о котором забывают: AMI по умолчанию льёт много событий, и большая часть вашей CRM не нужна. В manager.conf для пользователя можно задать eventfilter и ограничить классы read, чтобы скрипт получал только нужное. Фильтр помогает сократить поток и обработку лишних сообщений; он не заменяет проверку событий и полей, которые использует ваша CRM. Набор и поля событий между крупными версиями менялись, поэтому сверяйте их с документацией именно вашей ветки, а не со старым примером. Это скучная работа, но её стоит сделать один раз.
- Всплывающая карточка по входящему вызову
- Журнал звонков с длительностью и результатом
- Звонок по клику через Originate
- Статус занятости сотрудника
ARI: когда приложение само ведёт звонок
Asterisk REST Interface устроен иначе. Это REST API поверх встроенного HTTP-сервера Asterisk (настройки в http.conf и ari.conf) плюс WebSocket, по которому приходят события в JSON. Ключевое отличие — модель управления. Диалплан передаёт канал приложению через Stasis. Пока канал находится в Stasis, ARI-приложение управляет им через ресурсы channels, bridges и playbacks: может ответить, проиграть звук, собрать цифры или соединить с оператором. Когда канал выходит из Stasis, управление возвращается диалплану. Это не «Asterisk отключился», а другой участок логики звонка.
Это мощно и ровно поэтому опасно для простых задач. Если приложение недоступно, передача управления в Stasis может завершиться с ошибкой. Диалплан должен обработать результат и дать звонку понятный запасной маршрут; без такой ветки клиент действительно может не попасть к оператору. Приложение становится частью тракта только для каналов, направленных в Stasis, а не для всей телефонии. Для всплывающей карточки это избыточная ответственность: вы ставите бизнес-телефонию в зависимость от кода, которому нужно лишь знать, кто звонит. Для собственного голосового меню с запросами в CRM, умной маршрутизации по данным клиента или нестандартных очередей — наоборот, именно то, что нужно.
ARI передаёт события в JSON по WebSocket и предоставляет REST API; документация API формируется из описания интерфейса Asterisk. Но события не льются без разбора обо всех объектах: для канала подписка появляется при входе в Stasis, а для других ресурсов часто нужна отдельная подписка. Этот нюанс заметен, когда журнал внезапно «не видит» мосты или playback. Писать на нём приятнее. Но выбирать интерфейс по удобству разработчика, а не по требуемому контролю звонка, — классическая ошибка, после которой офис теряет звонки из-за того, что кто-то обновил библиотеку на сервере интеграции. Удобство кода — аргумент второго ряда. Первый ряд — что случится со звонком клиента, если этот код в три часа ночи перестанет отвечать, а утром его никто не перезапустит.
Что выбрать: короткая таблица решений
Я выбираю по одному вопросу: должна ли CRM управлять каналом или только знать о нём. Если только знать и изредка инициировать вызов — AMI. Если управлять — ARI, причём только для той части звонков, которую реально нужно отдавать приложению, а остальное пусть идёт обычным диалпланом. | Задача | AMI | ARI | |---|---|---| | Карточка при входящем | да, основной вариант | избыточно | | Журнал звонков | да | возможно, сложнее | | Звонок по клику | Originate | можно, но не нужно | | Своё голосовое меню | нет | да | | Маршрут по данным CRM | частично, через диалплан | да | | Падение скрипта | теряются события | теряются звонки в Stasis |
Последняя строка таблицы — самая важная. При AMI падение интеграции означает, что CRM временно ослепла: звонки идут, менеджеры разговаривают, вы просто не видите карточек и потом досинхронизируете журнал. При ARI сбой может затронуть звонки, переданные в Stasis, если в диалплане нет обработчика ошибки и запасного маршрута. Это разный класс аварии, и решение о нём должен принимать не программист, а тот, кто отвечает за продажи и поддержку клиентов. Я всегда задаю этот вопрос владельцу бизнеса прямо: готовы ли вы, что звонок клиента зависит от сервера интеграции? Обычно после этого вопроса выбор делается за минуту.
Комбинация тоже нормальна. В одной схеме можно оставить AMI для CRM и журнала, а ARI использовать только там, где нужно программное управление. Такая связка понятнее, когда у каждого интерфейса своя задача. Например, ARI для управления вызовами разбирает сценарий с контролем каналов. Главное — не пытаться сделать одной связкой всё сразу и не превращать сервер интеграции в единственную точку отказа для всей телефонии офиса. Чем меньше обязанностей у кода, тем реже он вас подводит. Если сомневаетесь — начните с AMI, а ARI добавьте потом, когда появится сценарий, которому он действительно нужен. Это дешевле. Проверено не раз.
Переподключение и журнал событий: без этого связка хрупкая
Любое долгоживущее соединение рвётся. Asterisk перезапустили, сеть моргнула, сервер интеграции ушёл в перезагрузку после обновлений. Клиент обязан это заметить и восстановиться сам. Для AMI это значит: периодическое действие Ping с таймаутом ответа, при отсутствии ответа — закрыть сокет, переподключиться с нарастающей паузой и снова пройти Login. Для ARI следите за WebSocket и после разрыва восстанавливайте соединение с /ari/events и именем приложения. После переподключения проверьте, что приложение зарегистрировано и получает нужные события. Протокол сам по себе не обещает вашему коду доставку пропущенных сообщений задним числом.
Второе — журнал. Каждое полученное событие, которое влияет на CRM, пишите в локальный журнал до того, как отправлять в CRM. Если API CRM недоступно, событие не должно пропасть: оно ждёт в очереди и уходит позже. У каждого канала Asterisk есть собственный UniqueID; один разговор при переводах и создании новых каналов может затрагивать несколько каналов. Используйте Uniqueid или Linkedid в AMI и id канала в ARI как часть своей модели связей, а для повторной отправки задайте CRM устойчивый ключ идемпотентности. Без этого первый же сбой CRM превращается в дыры в журнале звонков, которые никто не восстановит. Для небольшого офиса хватит очереди в локальной базе SQLite или даже в файле: важна гарантия, а не красота архитектуры.
Третье — сверка. Раз в сутки сравнивайте журнал интеграции с CDR самого Asterisk. Расхождение — сигнал, что вы что-то теряете, и лучше узнать об этом от скрипта, чем от руководителя отдела продаж. И запускайте интеграцию как службу systemd с автоматическим перезапуском, а не в screen под чьей-то учётной записью: я до сих пор нахожу такие процессы, которые живут с позапрошлого года и которые никто не решается остановить. Сверка занимает десяток строк кода. Зато экономит часы разбирательств. Проверено не раз на практике.
- Ping с таймаутом и переподключение с паузой
- Повторный Login или подписка приложения после обрыва
- Локальная очередь событий до отправки в CRM
- Идентификатор звонка как ключ против дублей
- Ежедневная сверка с CDR
- Запуск как служба systemd с перезапуском
Разбор условной «Проба-Снаб»
Условная «Проба-Снаб» продаёт лабораторное оборудование, а звонки для неё — важный канал продаж. Asterisk у них стоял давно, CRM подключили через скрипт, который подрядчик написал на ARI: все входящие заводились в Stasis, скрипт искал номер в CRM, открывал карточку и только потом отправлял звонок в очередь менеджеров. Жалобы были две: карточка открывается не всегда, а иногда звонок просто обрывается после гудка. Второе продажи списывали на оператора связи. Разбирать начали с журналов Asterisk и скрипта за две недели.
Журналы показали простую вещь. Скрипт не переподключался к WebSocket: после каждого перезапуска Asterisk он продолжал работать, но событий не получал, и звонки, попавшие в Stasis, ждали команду, которая не приходила. А медленный ответ API CRM задерживал соединение с менеджером на несколько секунд, часть клиентов не дожидалась. В журнале разобранного сценария обнаружились вызовы, которые не доходили до менеджеров. Скрипт формально оставался запущенным, но после обрыва WebSocket уже не получал события. Метрики и логи здесь полезнее уверенного статуса «процесс работает».
В примере схему переделали так: входящие вернули в обычный диалплан с очередью, Stasis убрали из этого сценария. Входящие вернулись в обычный диалплан с очередью, Stasis убрали полностью. Карточку и журнал отдали AMI: отдельный пользователь в manager.conf с доступом только с адреса сервера интеграции, фильтр событий, периодический Ping с контролем ответа, локальная очередь в SQLite и отправка в CRM с повтором. Служба systemd, ежедневная сверка с CDR и уведомление при расхождении. После изменений событие сначала записывается в локальную очередь, затем отправляется в CRM; при недоступности CRM повторная отправка не должна создавать дубль. Такой пример показывает логику ремонта, но не обещает нулевые потери без измерений на конкретной станции.
Безопасность интерфейсов и что дальше
И AMI, и ARI дают полный контроль над станцией в пределах выданных прав. Поэтому они не должны быть доступны из интернета ни при каких условиях. Порт AMI и HTTP-сервер Asterisk я закрываю межсетевым экраном, оставляя доступ только с сервера интеграции; в manager.conf для пользователя задаю permit и deny по адресу, права read и write — минимальные. Пароли длинные и разные для каждого приложения, а не один admin на всё. Если связь идёт между площадками, используйте шифрование: AMI поддерживает TLS, HTTP-сервер — HTTPS.
Отдельно проверьте права AMI. Для карточки не нужны write-права на классы command и config: command позволяет выполнять команды CLI, а config связан с изменением конфигурации. Не выдавайте их «на всякий случай». Если учётные данные интеграции утекут, лишние полномочия расширят ущерб; доступные действия зависят от конфигурации Asterisk. Проверьте и сам сервер интеграции: на нём не должно быть лишних сервисов, а обновления должны ставиться регулярно — он теперь часть периметра телефонии, и относиться к нему стоит соответственно, а не как к временной поделке подрядчика.
Итог простой: выбирайте интерфейс по нужному контролю над звонком, пишите связку как службу с переподключением, журналом и сверкой, и закрывайте её от всего мира. Когда выбираете интерфейс, сначала определите, должен ли код только сообщать о звонке или менять его ход. Затем проверьте права, сценарий возврата в диалплан и восстановление соединения после сбоя. Начинать лучше с журнала реальных событий вашей станции: там обычно быстро видно, какой участок отвечает за потерю данных.
Частые вопросы
Что проще для всплывающей карточки клиента — AMI или ARI?
AMI. Карточке нужно только событие о входящем вызове, управлять каналом не требуется, а падение скрипта не затрагивает сами звонки.
Когда без ARI не обойтись?
Когда приложение само ведёт звонок: собственное голосовое меню, маршрутизация по данным CRM, нестандартные мосты и очереди.
Можно ли использовать AMI и ARI одновременно?
Да. Частый вариант — AMI для CRM и журнала, ARI для одного сценария, где нужно программное управление звонком.
Как не терять события при перезапуске Asterisk?
Проверять живость соединения (Ping в AMI, состояние WebSocket в ARI), переподключаться автоматически, писать события в локальную очередь и сверять журнал с CDR.
Можно ли открыть порт AMI наружу для облачной CRM?
Нет. Доступ только с доверенного сервера интеграции, ограничение по адресу в manager.conf и шифрование при связи между площадками.
Источники
- Asterisk Manager Interface (AMI) — Настройка manager.conf, TCP-порт по умолчанию, действия и классы read/write: https://docs.asterisk.org/Configuration/Interfaces/Asterisk-Manager-Interface-AMI/The-Asterisk-Manager-TCP-IP-API/
- Asterisk REST Interface (ARI) — Stasis, каналы, модель событий и WebSocket: https://docs.asterisk.org/Configuration/Interfaces/Asterisk-REST-Interface-ARI/Introduction-to-ARI-and-Channels/
- Asterisk Configuration for ARI — Настройки HTTP/HTTPS-сервера и ARI в http.conf и ari.conf: https://docs.asterisk.org/Configuration/Interfaces/Asterisk-REST-Interface-ARI/Asterisk-Configuration-for-ARI/
- Asterisk AMI v2 Specification — Права классов, включая command и config, и настройки AMI: https://docs.asterisk.org/Configuration/Interfaces/Asterisk-Manager-Interface-AMI/AMI-v2-Specification/
- Asterisk Call Detail Records (CDR) — Назначение CDR и записи детализации вызовов: https://docs.asterisk.org/Configuration/Reporting/Call-Detail-Records-CDR/
- systemd.service — Настройки Restart и поведения служб: https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
