Задача
Ситуация, знакомая всем, кто сопровождает боевую базу: нужно посмотреть данные. Не отчётом, не через интерфейс, а именно кодом — сделать запрос к регистру, проверить содержимое реквизита, прогнать структуру документа через функцию и посмотреть, что получится.
В нормальном мире это делается консолью кода: открыл, написал, выполнил. В моём — сервер на Linux, доступ по ssh, графической сессии нет, а до кассиров, которых нельзя тревожить, полтора часа разницы во времени.
Я перебрал все способы, которые пришли в голову. Ниже — результаты по убыванию пригодности, включая отрицательные. Отрицательные, по-моему, ценнее: они экономят вечер, который я потратил зря.
Платформа 8.3.27, УТ 11.5, сервер на Linux, всё в пакетном режиме.
Способ 1: HTTP-метод в расширении
Работает. Единственный надёжный вариант.
Идея простая: добавляем в расширение HTTP-сервис с методом, который принимает запрос, выполняет нужный код на сервере и возвращает результат в JSON. Дальше дёргаем его обычным curl.
Что именно нужно сделать
Здесь лежит первая мина, и на ней застревают почти все. Написать функцию-обработчик в модуле недостаточно. Маршрут не появится, и вы будете получать 404, перечитывая код в поисках опечатки.
Нужны две вещи одновременно:
- Функция-обработчик в
Module.bslHTTP-сервиса; - Описание маршрута в XML сервиса: элементы
<URLTemplate>и вложенный<Method>, где указано имя обработчика и HTTP-глагол.
XML сервиса лежит в дампе расширения рядом с модулем. Если вы правите расширение из командной строки (см. мою предыдущую статью про пакетный режим), то это просто ещё один файл в каталоге дампа.
Обработчик выглядит так:
Функция ВыполнитьЗапросGET(Запрос)
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Результат = Новый Структура;
// ... здесь ваш код: запрос, чтение регистра, что угодно ...
Результат.Вставить("data", ДанныеРезультата);
Ответ.УстановитьТелоИзСтроки(
ЗначениеВJSON(Результат),
КодировкаТекста.UTF8
);
Возврат Ответ;
КонецФункции
Дальше вызов:
curl -u "<пользователь>:<пароль>" \
"http://127.0.0.1/<база>/hs/<корень сервиса>/<метод>"
Грабли этого способа
Маршруты кэшируются по сессии. Первый вызов свежесозданного метода вполне может отдать 404, хотя всё сделано правильно. Не бросайтесь искать ошибку — подождите секунд двадцать и повторите. Я успел дважды перезалить расширение, прежде чем понял, что дело было только в этом.
Basic-авторизация обязательна, и пользователь должен иметь права на выполнение того, что вы там написали. Ошибка прав приходит не как 403, а как невнятная 500 с текстом исключения в теле — читайте тело ответа целиком.
Сертификаты. Если внешний адрес базы требует клиентский сертификат, то при обращении с самого сервера на http://127.0.0.1 он не нужен — это сильно упрощает жизнь при отладке.
Почему это лучший вариант
- Код выполняется в полноценном серверном контексте, доступно всё;
- результат приходит в структурированном виде, его можно сразу разбирать
jq; - вызов идемпотентен и повторяем, его легко положить в скрипт;
- никаких графических подсистем, никаких модальных окон.
Куда безопасно вешать такой метод
Отдельное соображение, которое я вывел на своей шкуре. Временный диагностический метод надо вешать в самое маленькое непрофильное расширение, какое есть в базе.
Логика простая: правка расширения означает применение изменений к базе данных, а это риск. Если вы ошибётесь в расширении, которое обслуживает кассы, вы остановите торговлю. Если ошибётесь в расширении, которое считает что-нибудь третьестепенное и к кассам отношения не имеет, — цена ошибки близка к нулю.
У меня для этого выделено расширение с логикой одной второстепенной подсистемы: оно маленькое, редко меняется и ни на что критичное не влияет. Все временные методы живут там.
И обязательно: вынести токен доступа в константу, а не хардкодить в модуле. Мой временный метод переотправки данных до сих пор живёт в боевом расширении с захардкоженным токеном, потому что «потом уберу». Не делайте как я.
Способ 2: внешняя обработка через /Execute
Не работает. Это главный отрицательный результат статьи.
Команда выглядит ровно так, как нужно:
1cv8 ENTERPRISE /S <сервер>\<база> /N <пользователь> /P <пароль> \
/Execute /tmp/myproc.epf
Документация и здравый смысл подсказывают, что обработка сейчас выполнится. Она не выполнится.
/Execute только открывает обработку. Тело модуля объекта при этом не исполняется — оно вообще не предназначено для автозапуска. Логика, которую обычно вешают на открытие, живёт в ПриОткрытии, а это метод формы. Если обработка без формы — формы нет, метода нет, вызывать нечего. Процесс открывает пустоту и завершается.
Естественное решение — собрать обработку с формой, чтобы ПриОткрытии появился. И вот здесь вторая стена.
Способ 3: собрать .epf с формой из исходников
Не работает. Точнее, не работает у меня, и я не нашёл способа обойти.
Логика была такая: раз обработка нужна с формой, соберём её из файлов пакетной командой:
DESIGNER /LoadExternalDataProcessorOrReportFromFiles /tmp/proc.xml /tmp/proc.epf
Для обработок без формы эта команда отрабатывает нормально. Как только в исходниках появляется форма, приходит:
Исключение XDTO при чтении Form.xml
Причём — и это важная деталь — ошибка воспроизводится на нетронутом дампе. То есть берём готовую обработку с формой, выгружаем её в файлы той же самой командой той же самой платформы, ничего не правим и собираем обратно. Не собирается.
Я потратил на это вечер, перебирая версии, кодировки и структуру каталога. Вывод: связка «выгрузить-собрать» для обработок с формой в пакетном режиме на моей версии платформы просто не замкнута.
Если у кого-то получилось — расскажите в комментариях, мне это до сих пор интересно.
Способ 4: готовые консоли кода
Не работает в headless.
Очевидная мысль: зачем изобретать, если есть «Консоль кода» из «Инструментов разработчика» — обработка, которая ровно для этого и написана.
Мысль разбивается о два обстоятельства.
Первое: чтобы её запустить, нужен способ выполнить внешнюю обработку. См. способы 2 и 3 — его нет.
Второе, более фундаментальное: консоль кода из «Инструментов разработчика» тянет за собой серверный модуль редактора кода. В headless-окружении он не поднимается, и обработка отказывается работать ещё на инициализации.
Консоли кода рассчитаны на интерактивную работу в толстом клиенте. В пакетном режиме на Linux-сервере им делать нечего.
Способ 5: регламентное задание
Работает, но неудобно. Упоминаю для полноты.
Можно завести в расширении регламентное задание с нужным кодом и запустить его вручную через административные средства. Код выполнится в серверном контексте, ограничений почти нет.
Минусы, из-за которых я этим не пользуюсь:
- результат некуда положить. Регламентное задание ничего не возвращает — надо писать в регистр сведений, в журнал регистрации или во внешний приёмник, а потом это ещё читать;
- обратная связь плохая. Ошибка выполнения приедет в журнал регистрации, который на боевой базе шумный;
- цикл правки долгий. Каждая итерация — это правка расширения и применение к базе, то есть минуты вместо секунд.
Для однократной массовой операции — годится. Для «посмотреть, что в реквизите» — избыточно.
Отдельный приём: проверить, что 1С шлёт наружу
Смежная задача, которая решается тем же HTTP-методом и заслуживает упоминания.
Типичный вопрос при отладке интеграции: что именно 1С отправляет во внешнюю систему? Ждать живого документа неудобно — он придёт когда придёт, а данные в нём будут те, какие будут.
Решение: метод переотправки, который заново собирает структуру исходящего сообщения за указанный период и отправляет её в приёмник, ничего не записывая в 1С.
curl -X POST "http://127.0.0.1/<база>/hs/<корень>/resend?from=YYYYMMDDHHMMSS&to=YYYYMMDDHHMMSS"
Дальше полное тело запроса смотрится уже на стороне приёмника, в его логах. Никакой возни с отладкой сериализации внутри 1С.
Три условия, без которых приём опасен:
- Приёмники должны быть идемпотентны. У меня они дедуплицируют по идентификатору документа и фискальному номеру — повторная отправка данные не задваивает. Если приёмник этого не умеет, переотправка испортит статистику.
- Резать периоды мелко. У меня получалось около секунды на документ, поэтому периоды больше получаса неудобны.
- В 1С ничего не пишется. Метод только читает и отправляет. Как только он начнёт что-то записывать, это уже не диагностика.
Отдельный вопрос — убедиться, что приёмник не просто принял, а записал нужные поля. Живым документом это не проверить: он придёт один раз и создаст дубль при повторе.
Способ, который у меня прижился: отправить в приёмник технический документ со сгенерированным uuidgen идентификатором, посмотреть строку в базе приёмника и удалить её — каскад уберёт связанные записи. Важная деталь: у нас приёмник отвергает идентификаторы со словом «test» в составе, так что генерируйте нейтральные.
Сводная таблица
| Способ | Результат | Комментарий |
|---|---|---|
| HTTP-метод в расширении | работает | Нужны и модуль, и <URLTemplate>/<Method> в XML |
Внешняя обработка /Execute |
не работает | Только открывает, тело модуля не исполняется |
Сборка .epf с формой из файлов |
не работает | Исключение XDTO на Form.xml даже на нетронутом дампе |
| Готовые консоли кода | не работает | Требуют серверный модуль редактора, в headless не поднимается |
| Регламентное задание | частично | Работает, но результат некуда вернуть, цикл долгий |
Выводы
Если вам нужно выполнять произвольный код в боевой 1С на Linux-сервере без графической сессии — стройте HTTP-метод в расширении и не тратьте время на остальное. Я потратил, и остальное не работает.
Три вещи, которые стоит запомнить:
- Функции в модуле недостаточно — без
<URLTemplate>и<Method>в XML маршрута не будет, а 404 вы будете списывать на что угодно, кроме этого. - Первый вызов нового метода может дать 404 из-за кэша маршрутов — подождите двадцать секунд, прежде чем искать ошибку.
- Вешайте временные методы в самое неважное расширение — цена ошибки при применении изменений должна быть минимальной. Расширение, обслуживающее кассы, для экспериментов не подходит.
И главное про отрицательные результаты: /Execute не выполняет код, сборка обработки с формой из файлов не работает, консоли кода в headless не заводятся. Три вечера, сэкономленные читателю.
Платформа 8.3.27, УТ 11.5, сервер 1С на Linux. Всё проверено на боевых базах розничной сети.
Вступайте в нашу телеграмм-группу Инфостарт