Asterisk: pbx_builtins.c Dialplan execution limit reached (Max loop depth exceeded)
- Ошибка в журнале:
ERROR: pbx_builtins.c: Dialplan execution limit reached (Max loop depth exceeded). - Вызов мгновенно завершается при переходе между контекстами extensions.conf.
- Абонент слышит короткие гудки или сообщение о техническом сбое.
- В CLI фиксируется лавинообразный вывод сотен строк выполнения одного и того же extension за миллисекунды.
1. Анализ трейса выполнения диалплана
Включите расширенную детализацию диалплана:
asterisk -rvvv
core set verbose 5Найдите циклическую конструкцию в логе выполнения (например, переход `Goto(context,exten,1)` сам на себя):
-- Executing [s@sub-check:1] Goto("PJSIP/101-0001", "sub-check,s,1")
-- Executing [s@sub-check:1] Goto("PJSIP/101-0001", "sub-check,s,1")
-- ERROR: pbx_builtins.c: Dialplan execution limit reached2. Исправление циклических конструкций в extensions.conf
Всегда добавляйте счетчик итераций при организации циклов в диалплане:
[macro-retry-dial]
exten => s,1,Set(LOOP_CNT=0)
same => n(loop_start),Set(LOOP_CNT=$[${LOOP_CNT} + 1])
same => n,GotoIf($[${LOOP_CNT} > 3]?loop_abort)
same => n,Dial(PJSIP/100,10)
same => n,GotoIf($["${DIALSTATUS}" != "ANSWER"]?loop_start)
same => n,Return()
same => n(loop_abort),Verbose(1, [WARNING] Exceeded max retries for call)
same => n,Playback(im-sorry)
same => n,Hangup(16)3. Проверка парных вызовов GoSub и Return
Убедитесь, что каждый переход GoSub() завершается командой Return(), предотвращая переполнение стека вызовов:
[sub-crm-lookup]
exten => s,1,NoOp(CRM Lookup)
same => n,Set(CALLERID(name)=VIP_${CALLERID(num)})
same => n,Return() ; <-- ОБЯЗАТЕЛЬНО4. Перезагрузка диалплана
asterisk -rx "dialplan reload" Частые вопросы (FAQ)
Каков максимальный лимит глубины цикла в диалплане по умолчанию?
По умолчанию лимит защитного счетчика Asterisk PBX составляет 1000 итераций для предотвращения зависания процессорного ядра.
В чем разница между Goto и GoSub?
Goto выполняет безусловный прыжок на метку без сохранения точки возврата. GoSub сохраняет адрес возврата в стек, требуя обязательного вызова Return(). Пропущенный Return приводит к утечке памяти стека канала.
Как сбросить застрявший зацикленный канал?
Найдите канал через core show channels concise и завершите его: channel request hangup <Channel_Name>.
Можно ли изменить максимальный лимит глубины цикла?
Параметр жестко зашит в исходном коде main/pbx.c (константа MAX_EXPAND_DEPTH), так как 1000 шагов более чем достаточно для любой логики без рекурсивных ошибок.