Перейти к содержанию

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 API
  • docs/domains/smart-actions/actions-reference.md — справочник всех действий
  • admin.md — пользовательская документация