FAQ: Lua pcall + SMART:execute_action — какие ошибки перехватываются¶
Тип: FAQ для поддержки и администраторов Источник тикетов: «Ошибка при создании задачи через Lua-скрипт: исключение не перехватывается pcall()»
1. Симптомы¶
Администратор/разработчик жалуется:
- «Обернул SMART:execute_action("CreateTask", ...) в pcall, но ошибка не ловится»
- «Lua-скрипт падает с необработанным исключением, хотя стоит pcall»
- «Как правильно обрабатывать ошибки при создании задач из Lua?»
2. Как работает перехват ошибок¶
Архитектура вызова¶
Lua pcall(func)
→ NLua bridge
→ SmartActionScriptApi.execute_action()
→ BaseScriptApi.Call<T>() ← точка перехвата
→ PackDelegateExecutor.ExecuteWithResult()
→ [действие: CreateTask, SendPush, и т.д.]
Что ловит pcall ✅¶
| Тип ошибки | Пример | pcall ловит? |
|---|---|---|
| Ошибка в пользовательском Lua-коде | nil + 1, обращение к nil-полю |
✅ |
| Неверное имя действия | execute_action("НесуществующееДействие", ...) |
✅ |
| Неверный тип контекста | execute_action("CreateTask", id, "unknown", ...) |
✅ |
| Ошибка бизнес-логики при выполнении действия | Валидация ДП, отсутствие прав | ✅ |
SQL-ошибки в SQL:query(), SQL:scalar() |
Синтаксическая ошибка в запросе | ✅ |
| Ошибка делегата действия | Исключение внутри PackDelegateExecutor |
✅ |
Что pcall НЕ ловит ❌¶
| Тип ошибки | Причина | pcall ловит? |
|---|---|---|
| Синтаксическая ошибка Lua | Ошибка при компиляции, до выполнения | ❌ |
| Ошибка маршалинга параметров NLua | Невозможность конвертации типов на границе Lua↔C# | ❌ |
SEHException (.NET 9, x64) |
Исключение до входа в обёртку Call() |
❌ |
| Ошибки в обработчиках исключений | Если само сохранение исключения в Lua state падает | ❌ |
Особенность .NET 9¶
В .NET 9 (x64) изменилось поведение проброса исключений из NLua:
- Раньше: LuaException с InnerException = оригинальное .NET исключение
- Сейчас: SEHException, оригинальное исключение теряется
Обходное решение в коде 1Формы: все API-методы (SMART:*, SQL:*) кэшируют исключение в глобальную переменную __CALL_EXCEPTION__ через BaseScriptApi.Call<T>(). Движок ScriptEngine перехватывает SEHException и восстанавливает оригинал.
3. Правильный паттерн обработки ошибок¶
Рекомендуемый подход¶
local success, result = pcall(function()
return SMART:execute_action("CreateTask", nil, "task", {
SubcatID = 123,
TaskName = "Новая задача",
-- ...параметры...
})
end)
if not success then
-- result содержит строку с сообщением об ошибке
print("Ошибка создания задачи: " .. tostring(result))
-- Можно записать в лог или выполнить альтернативное действие
else
-- result содержит возвращённое значение (например, ID созданной задачи)
print("Задача создана: " .. tostring(result))
end
Асинхронные вызовы — особый случай¶
Если async = true, execute_action возвращает nil немедленно:
- Ошибки произойдут позже, в фоне
- pcall не перехватит асинхронные ошибки
- Для контроля используйте синхронный режим или проверяйте результат отдельно
4. Частые причины «pcall не ловит»¶
| Ситуация | Объяснение | Решение |
|---|---|---|
| Синтаксическая ошибка в скрипте | Скрипт не компилируется → pcall не вызывается | Исправить синтаксис, проверить в TestCases |
| Ошибка в коде ВНЕ pcall | Исключение до/после блока pcall | Обернуть весь код в pcall |
| Неверный тип параметра | NLua не может конвертировать → SEHException | Привести типы явно: tonumber(), tostring() |
| Ошибка при async=true | Асинхронная ошибка не возвращается в pcall | Использовать синхронный вызов для отладки |
5. Отладка через TestCases¶
SmartExpressionTestCases (SmartExpressionTestCases в БД) позволяют тестировать Lua-скрипты:
- Задать набор входных параметров
- Запустить скрипт в безопасном контексте
- Увидеть полный вывод (print) и исключения
API: GET /admin/smart/recurrences/execute/{id} — ручной запуск для проверки.
6. Что запросить у клиента¶
- Полный текст Lua-скрипта
- Сообщение об ошибке (из логов или UI)
- ID задачи / категории, в контексте которой запускался скрипт
- Версия платформы (важно для .NET 9)
7. Когда эскалировать¶
- Если
pcallдействительно не ловит ошибку внутриSMART:execute_action→ L3 (возможный баг NLua/.NET 9) - Если ошибка при компиляции скрипта → помочь клиенту с синтаксисом
- Если ошибка в бизнес-логике действия → L2 (проверить настройки категории/ДП)
8. Связанные документы¶
docs/domains/smart-actions/backend.md— SmartScriptService, Lua APIdocs/domains/smart-actions/actions-reference.md— справочник всех действийadmin.md— пользовательская документация