Очередь Asterisk: как делить звонки в офисе
АйТи Фреш
Серверы и инфраструктура

Как распределить входящие звонки в Asterisk

Автор: , директор ООО «АйТи-Фреш» · · ~12 мин чтения
Круговая схема с жетонами показывает распределение звонков в очереди Asterisk
Хорошая очередь распределяет работу и оставляет звонящему выход.

Чтобы распределять звонки в Asterisk, подберите стратегию под работу отдела, задайте время дозвона и общий лимит ожидания, а каждому выходу из очереди назначьте понятный маршрут. Покажу, где проверить конфигурацию и как считать пропущенные, не выдавая примерные цифры за результат.

Почему все звонки достаются одному оператору

Сценарий узнаваемый. В отделе пять человек, а звонки берёт один, самый быстрый на руку, или первый в списке. Остальные сидят спокойно, а вечером этот один уходит с ощущением, что работал за всех. Руководитель смотрит на отчёт и не понимает, почему при пяти операторах клиенты ждут. Когда нас зовут на ИТ-аутсорсинг для офиса с такой телефонией, первым делом открываем queues.conf и почти всегда находим там стратегию по умолчанию или linear, выбранную «чтобы был порядок».

У ringall (это стратегия по умолчанию в Asterisk) логика простая: звонят все доступные участники сразу, отвечает тот, кто первым снял трубку. В маленькой команде это превращается в соревнование реакции, и выигрывает всегда один и тот же человек. У linear другая беда: звонок всегда начинается с первого участника в списке, и пока он свободен, до остальных очередь доходит редко. Обе стратегии рабочие, но выбор без понимания графика и нагрузки быстро превращает очередь в лотерею.

Вторая половина жалобы — абоненты долго ждут без выхода. Очередь без общего таймаута и без альтернативного маршрута держит человека под музыку сколько угодно. Ирония в том, что такая очередь в отчётах выглядит прекрасно: пропущенных нет, все «дождались». Просто часть из них положила трубку на пятой минуте, и это записано как ABANDON, который никто не смотрит. Если звонок приходит через IVR, логика меню должна вести в очередь только в рабочее время; подробнее о маршрутизации рассказываем в материале про схему IVR в Asterisk.

Стратегии очереди в queues.conf: какую выбрать

Стратегию задаёт параметр strategy в секции очереди файла queues.conf. Диалплан отправляет вызов в очередь приложением Queue(). Я начинаю выбор не с названия красивого алгоритма, а с правил отдела: должны ли сотрудники получать сопоставимое число звонков, важна ли скорость ответа или нужен основной оператор с резервом. Алгоритм распределяет вызовы, но сам по себе не учитывает сложность разговора, длительность оформления и качество ответа. | Стратегия | Как работает | Когда подходит | |---|---|---| | ringall | звонят все свободные сразу | 2–3 человека, важна скорость ответа | | rrmemory | по кругу, помнит, на ком остановились | равная нагрузка в отделе | | leastrecent | тому, кто дольше всех без звонка | длинные разговоры, нужен отдых | | fewestcalls | тому, у кого меньше принятых | выравнивание по количеству | | linear | всегда по порядку списка | есть старший и резерв | | random / wrandom | случайный выбор; wrandom учитывает penalty участника | только если есть причина |

Для небольшой команды с одинаковыми обязанностями я обычно начинаю с rrmemory: очередь продолжает распределение с участника, на котором остановилась. leastrecent выбирает того, кто дольше не получал вызов. Ни один вариант не делит нагрузку идеально: fewestcalls сравнивает число принятых звонков, а не минуты разговора и не сложность заявки. Три длинных разговора могут вымотать сильнее десяти коротких, и конфигурация этого не угадает.

linear уместна, если порядок участников намеренный: сначала дежурный, затем резерв. Она опирается на порядок, заданный конфигурацией, поэтому перестановка строк может изменить маршрутизацию. После правки проверьте актуальную для вашей сборки процедуру перезагрузки. В типовой консоли Asterisk конфигурацию очередей перечитывают командой module reload app_queue.so, затем проверяют queue show; отдельная команда queue reload в статье была бы неточной. Перед изменением стратегии я сохраняю старые значения и проверяю поведение на тестовом вызове.

ringall в отделе из пяти человек превращается в соревнование на скорость реакции. Победитель всегда один, и к пятнице он выгорает.
Как распределить входящие звонки в Asterisk — схема
Схема к статье. Открыть схему в полном размере

Таймауты очереди: timeout, retry, wrapuptime и общее ожидание

Таймаутов в очереди несколько, и их постоянно путают. timeout в queues.conf — сколько секунд звонит телефон одного оператора, прежде чем очередь решит, что он не ответил. retry — пауза перед следующей попыткой обзвона. wrapuptime — время после завершения разговора, когда оператору не дают новый звонок, чтобы он успел записать заявку. А общий таймаут ожидания абонента в очереди задаётся отдельно, аргументом приложения Queue() в диалплане.

[support]
strategy = rrmemory
timeout = 15
retry = 3
wrapuptime = 20
ringinuse = no
maxlen = 8
joinfull = no
announce-frequency = 60
announce-holdtime = no
servicelevel = 30
joinempty = paused,unavailable,invalid
leavewhenempty = paused,unavailable,invalid
context = support-exit
member => PJSIP/301
member => PJSIP/302

timeout=15 означает время попытки дозвона участнику, а не общий срок ожидания абонента. Пятнадцать секунд — только отправная точка: длительность гудков зависит от телефонии и сценария, поэтому я проверяю её реальным звонком. retry задаёт паузу перед следующей попыткой, а wrapuptime — минимальный интервал после разговора перед новым вызовом этому участнику. Для заполнения карточки обращения может хватить 20–30 секунд, но это надо замерить на рабочем процессе, а не объявлять универсальной нормой.

ringinuse=no запрещает предлагать новый вызов участнику, который уже занят. Но результат зависит от того, видит ли Asterisk корректное состояние канала. Я проверяю участника командой queue show и тестовым звонком: название PJSIP само по себе не гарантирует правильный device state. При канале-обёртке или нестандартной маршрутизации может понадобиться отдельно настроить state_interface.

Выходы из очереди: таймаут, клавиша, пустая очередь

Очередь должна иметь понятный маршрут на случай ожидания, пустой группы и выхода по клавише. Общий таймаут задаётся аргументом приложения Queue() в диалплане; в примере ниже пятый аргумент — 180 секунд. Параметр context в queues.conf задаёт контекст, куда Asterisk передаёт нажатия во время ожидания. Если доступных участников нет, joinempty и leavewhenempty определяют, можно ли войти в очередь и что делать с уже ожидающим звонком.

[q-support]
exten => s,1,Answer()
 same => n,Queue(support,,,,180)
 same => n,GotoIf($["${QUEUESTATUS}" = "TIMEOUT"]?vm,1)
 same => n,GotoIf($["${QUEUESTATUS}" = "JOINEMPTY"]?vm,1)
 same => n,GotoIf($["${QUEUESTATUS}" = "LEAVEEMPTY"]?vm,1)
 same => n,Hangup()
exten => vm,1,VoiceMail(500@support)

[support-exit]
exten => 1,1,VoiceMail(500@support)

После выхода из Queue() проверьте ${QUEUESTATUS}. Документированные состояния включают TIMEOUT, FULL, JOINEMPTY, LEAVEEMPTY, JOINUNAVAIL и LEAVEUNAVAIL. Для каждого состояния задайте маршрут или понятное завершение; при неразобранном результате диалплан может просто перейти к следующему приоритету и закончить вызов. Обработчик TIMEOUT — не замена настройкам пустой очереди: это разные причины выхода и разные сценарии.

maxlen ограничивает число ожидающих; при joinfull=no новый вызов не присоединяется к заполненной очереди, а Queue() возвращает статус FULL. Значение восемь — пример для настройки, не рекомендация для любого отдела. Рассчитайте лимит по числу доступных операторов, средней длительности обслуживания и готовности перезванивать. Голосовая почта полезна лишь тогда, когда назначен ответственный и задан срок обработки.

Ветвление по QUEUESTATUS после Queue() обязательно. Иначе человек ждёт три минуты и получает короткие гудки.
Если звонки уходят одному оператору или абоненты застревают в ожидании, мы разберём очереди и диалплан, настроим проверяемые маршруты и отчёт по пропущенным. Для начала достаточно схемы входящего звонка и обезличенных журналов. Обсудить задачу
Обратите внимание: Выходы из очереди: таймаут, клавиша, пустая очередь — схема
Обратите внимание: Выходы из очереди: таймаут, клавиша, пустая очередь. Открыть схему в полном размере

Расписание, паузы и динамические участники очереди

Отдел живёт не по конфигу. Кто-то на обеде, кто-то на выезде, кто-то ушёл на совещание и забыл про телефон. Если участники очереди прописаны статически, очередь будет звонить на пустой стол каждый круг, тратя timeout на каждого. Поэтому я делаю операторов динамическими или, как минимум, даю им паузу. Приложения AddQueueMember, RemoveQueueMember и PauseQueueMember вешаются на служебные коды: оператор набирает код и выходит на обед или возвращается.

Для короткого перерыва пауза обычно удобнее удаления: участник остаётся в списке, а его состояние видно в queue show. Когда joinempty и leavewhenempty учитывают paused, можно не принимать новые звонки и вывести уже ожидающие, если все операторы на паузе. Это поведение нужно проверить на своей версии и с фактическим состоянием каналов. Я также задаю причину паузы, если используемая конфигурация её поддерживает: потом проще отличить обед от технической недоступности.

Расписание самой очереди проверяется до вызова Queue(), так же как в меню, через GotoIfTime. Вне рабочего времени звонок не должен попадать в очередь вовсе. Отдельный нюанс — обеденный перерыв: если весь отдел уходит обедать одновременно, на это время звонки лучше направить дежурному или в почту, а не держать людей в очереди с музыкой. Ни один клиент ещё не сказал спасибо за мелодию, прослушанную до конца.

Контроль пропущенных: queue_log и уровень обслуживания

Asterisk по умолчанию пишет журнал очереди в /var/log/asterisk/queue_log, если логирование не перенастроено. Строки разделены символом |: сначала идут UNIX-время, идентификатор канала, очередь, участник, тип события и его параметры. ENTERQUEUE отмечает вход, CONNECT — соединение с оператором, ABANDON — уход абонента до ответа, EXITWITHTIMEOUT — истечение таймаута, а COMPLETEAGENT и COMPLETECALLER — завершение разговора оператором или абонентом. В отличие от CDR, queue_log показывает этапы ожидания и маршрутизации.

# суммарно в текущем файле: брошенные и вышедшие по таймауту
grep -E 'ABANDON|EXITWITHTIMEOUT' /var/log/asterisk/queue_log | wc -l
# кто чаще не берёт трубку
grep RINGNOANSWER /var/log/asterisk/queue_log | awk -F'|' '{print $4}' | sort | uniq -c

Первая команда считает записи во всём текущем файле, а не «за сегодня»: queue_log не содержит дату в читаемом виде, первое поле — UNIX-время. Для дневной статистики отберите интервал по этому полю или используйте систему отчётности, учитывающую ротацию файлов. Вторая команда выводит участника из четвёртого поля строк RINGNOANSWER. Параметр servicelevel задаёт порог ожидания для показателя SL; queue show показывает долю вызовов, обработанных в пределах этого порога. Сам порог выбирайте по обещанию клиенту и фактической нагрузке, а не по чужому шаблону.

Журнал ENTERQUEUE обычно содержит Caller ID Number, если идентификатор доступен и его запись не ограничена настройками приватности. Сверьте его с CDR по идентификатору вызова, назначьте ответственного за обратный звонок и фиксируйте результат. Не обещаю, что перезвон «в течение часа» вернёт большую часть клиентов: это зависит от отрасли и скорости реакции. Для контроля можно связать очередь с метриками качества звонков Asterisk и смотреть динамику по своим данным.

Пример политики для небольшого отдела

Возьмём условную небольшую компанию с шестью сотрудниками на входящей линии. Это учебный пример конфигурации, а не история конкретного клиента или замер результата. В исходном сценарии стоит ringall, все участники статические, общего лимита ожидания и маршрута по QUEUESTATUS нет. В обед телефоны остаются доступными для очереди, хотя ответить некому. Такая схема проверяется не по впечатлению руководителя, а по queue_log и тестовым вызовам.

В учебном варианте я бы проверил rrmemory как начальный выбор, выставил короткий timeout дозвона и измерил фактическое время заполнения карточки, прежде чем назначать wrapuptime. На обед оператор ставит паузу, joinempty и leavewhenempty выводят вызов на резервный маршрут, а общий таймаут в Queue() ведёт к голосовой почте с назначенным ответственным. maxlen и интервалы здесь подбираются после оценки потока. Срок внедрения зависит от текущего диалплана и телефонии, поэтому обещать фиксированные три дня без обследования было бы нечестно.

После запуска я сравниваю показатели за сопоставимые рабочие дни: сколько вызовов вошло, сколько обработано, сколько оставлено и сколько покинуто до ответа. Если доля ABANDON не меняется, значит, одной сменой стратегии проблему не решили — надо смотреть расписание, число доступных операторов и длительность обслуживания. Важно не подменять результат красивой цифрой: цель — понятный маршрут для звонящего и своевременный обратный звонок. Для записи разговоров отдельно проверяют права и срок хранения.

Частые вопросы

Какую стратегию очереди Asterisk выбрать для небольшого отдела?

При одинаковых задачах начните с rrmemory и сравните распределение по queue_log. ringall звонит всем доступным участникам сразу, linear сохраняет порядок списка; ни одна стратегия не учитывает сложность разговора.

Чем timeout очереди отличается от таймаута Queue()?

timeout в queues.conf ограничивает попытку дозвона участнику. Аргумент timeout приложения Queue() ограничивает общее ожидание вызывающего в очереди.

Как включить выход из очереди по клавише?

Укажите параметр context в секции очереди и задайте в этом контексте маршрут для нажатия. Проверьте на тестовом вызове, что DTMF доходит и звонок действительно выходит.

Что означает QUEUESTATUS?

Это переменная с причиной выхода из Queue(), например TIMEOUT, FULL, JOINEMPTY, LEAVEEMPTY, JOINUNAVAIL или LEAVEUNAVAIL. Для нужных состояний настройте маршруты в диалплане.

Где смотреть пропущенные звонки очереди?

В queue_log: ABANDON отмечает уход абонента до ответа, EXITWITHTIMEOUT — выход по таймауту. Caller ID может быть в записи ENTERQUEUE; учитывайте доступность и ограничения идентификатора.

Столкнулись с похожей задачей? Обращайтесь — решим

Если у вас происходит что-то из описанного в этой статье — или любая другая проблема с ИТ-инфраструктурой, — обращайтесь в любое время. Мои специалисты и я лично разберём ситуацию, найдём настоящую причину и доведём до решения.

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи