Серверный код в 1С 8.3: от директивы &НаСервере до фонового задания

· 11 мин

Содержание

Чтобы запустить процедуру на сервере 1С, поставьте над ней директиву &НаСервере (или &НаСервереБезКонтекста) в модуле формы и вызовите её из клиентской процедуры обычным вызовом по имени. Платформа сама передаст управление на сервер, выполнит код и вернёт результат на клиент. Для общего модуля нужны флажки Сервер и Вызов сервера и ключевое слово Экспорт у процедуры.

Способов выполнить код на сервере несколько, и выбирают их по задаче. Нужно что-то прочитать из базы при нажатии кнопки — хватит серверной процедуры формы. Логика нужна в десяти формах — её выносят в общий модуль. Операция идёт минуты — её запускают фоновым заданием, чтобы не вешать интерфейс. Всё это работает одинаково в клиент-серверном и файловом варианте: в файловом «сервер» просто живёт внутри процесса клиентского приложения.

Где выполняется код: клиент, сервер и директивы компиляции

В управляемом приложении код формы делится на две части. Клиентская часть работает на компьютере пользователя и не видит базу данных. Серверная работает в рабочем процессе кластера и имеет доступ к запросам, объектам и регистрам.

Где выполнится конкретная процедура модуля формы, решает директива компиляции перед её объявлением.

ДирективаГде выполняетсяДанные формыКогда применять
&НаКлиентеклиентдоступныобработчики кнопок, диалоги, работа с интерфейсом
&НаСервересервердоступны (передаются на сервер)нужно читать или менять реквизиты формы и обращаться к базе
&НаСервереБезКонтекстасервернедоступнырасчёт по параметрам, запрос к базе без обращения к форме
&НаКлиентеНаСервереБезКонтекстатам, откуда вызвалинедоступныобщие вычисления, нужные и клиенту, и серверу

Процедура без директивы в модуле формы считается серверной. Полагаться на это не стоит: явная директива читается проще и не путает коллег.

В общих модулях директив нет. Контекст задают флажки в свойствах модуля:

  • 🖥 Сервер — модуль компилируется на сервере;
  • 📞 Вызов сервера — его экспортные методы можно вызывать с клиента;
  • 💻 Клиент (управляемое приложение) — модуль работает на клиенте;
  • 🔗 Внешнее соединение — доступен при подключении через COM;
  • 🔐 Привилегированный — код выполняется без проверки прав.

Внутри модулей, которые компилируются в нескольких контекстах (модуль объекта, менеджера, общий модуль с флажками Клиент и Сервер), участки кода отделяют инструкциями препроцессора:

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
// код, которому нужна база данных
#КонецЕсли

Как вызвать процедуру на сервере из формы: параметры и возврат значения

Классическая связка — клиентский обработчик кнопки плюс серверная функция. Клиент собирает данные, сервер считает, клиент показывает итог.

&НаКлиенте
Процедура ПосчитатьОстаток(Команда)
    Остаток = ОстатокТовараНаСервере(Объект.Номенклатура, Объект.Склад);
    ПоказатьПредупреждение(, "Остаток: " + Формат(Остаток, "ЧДЦ=3; ЧН=0"));
КонецПроцедуры

&НаСервереБезКонтекста
Функция ОстатокТовараНаСервере(Знач Номенклатура, Знач Склад)
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ
    |    ЕСТЬNULL(СУММА(Т.КоличествоОстаток), 0) КАК Количество
    |ИЗ
    |    РегистрНакопления.ТоварыНаСкладах.Остатки(, Номенклатура = &Номенклатура И Склад = &Склад) КАК Т";
    Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
    Запрос.УстановитьПараметр("Склад", Склад);
    Выборка = Запрос.Выполнить().Выбрать();
    Выборка.Следующий();
    Возврат Выборка.Количество;
КонецФункции

Имя регистра и его измерения здесь условные: подставьте те, что есть в вашей конфигурации. Агрегатная функция СУММА гарантирует одну строку в результате, поэтому Выборка.Следующий() всегда вернёт запись.

Что можно передавать между клиентом и сервером

Параметры и результат сериализуются и едут по сети. Поэтому годится не любой тип.

  • ✅ Можно: примитивы (Строка, Число, Дата, Булево), ссылки на объекты базы, Структура, Массив, Соответствие, их фиксированные варианты, ХранилищеЗначения, данные формы.
  • ❌ Нельзя: СправочникОбъект, ДокументОбъект, ТаблицаЗначений, Запрос, РезультатЗапроса — эти типы живут только на сервере.

Нужна таблица на клиенте — перегоните её в массив структур или в реквизит формы типа «Таблица значений». Нужен объект целиком — работайте с ним на сервере, а на клиент верните только то, что надо показать.

Знач и параметры по ссылке

При вызове сервера с клиента параметр без Знач передаётся «по ссылке»: изменения, сделанные на сервере, вернутся на клиент. Платформа для этого гонит значение туда и обратно. Если серверу параметр нужен только для чтения, пишите Знач — это минус лишняя пересылка, особенно для больших структур и массивов.

Чем &НаСервере дороже &НаСервереБезКонтекста

При вызове &НаСервере платформа передаёт на сервер данные формы, а потом возвращает изменения. Для формы документа с табличной частью в 500 строк это ощутимый трафик на каждый клик.

Правило практика: если серверной процедуре не нужны реквизиты формы, ставьте &НаСервереБезКонтекста и передавайте ровно те значения, что нужны. В медленных сетях и на тонком клиенте через интернет разница видна невооружённым глазом.

Ещё один приём — объединять вызовы. Три подряд серверные функции из одного клиентского обработчика — это три сетевых обращения. Одна функция, которая вернёт Структуру с тремя значениями, — одно.

Вызов серверного кода из общих модулей и модулей объектов

Когда одна и та же серверная логика нужна в нескольких местах, её выносят в общий модуль. Порядок такой:

  1. В Конфигураторе создайте общий модуль, например РаботаСОстаткамиВызовСервера.
  2. В свойствах отметьте Сервер и Вызов сервера. Флажок Клиент не ставьте.
  3. Объявите функцию с ключевым словом Экспорт.
  4. С клиента вызывайте её через имя модуля: РаботаСОстаткамиВызовСервера.Остаток(Номенклатура, Склад).

Без флажка Вызов сервера клиент этот модуль не увидит. Без Экспорт метод не виден за пределами модуля. Удобная привычка — держать серверную логику в модуле только с флажком Сервер, а в модуле …ВызовСервера оставлять тонкие функции-обёртки. Так с клиента доступно лишь то, что вы осознанно открыли.

Модуль объекта и модуль менеджера

Модули объекта и менеджера справочника или документа выполняются на сервере, но вызвать их напрямую с клиента нельзя. Из формы элемента к модулю объекта обращаются так:

&НаСервере
Процедура ЗаполнитьПоОснованиюНаСервере()
    ДокументОбъект = РеквизитФормыВЗначение("Объект");
    ДокументОбъект.ЗаполнитьТовары(); // экспортная процедура модуля объекта
    ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");
КонецПроцедуры

Метод модуля менеджера вызывают в серверной процедуре через менеджер: Документы.РеализацияТоваровУслуг.ИмяМетода(...). Метод должен быть экспортным, а сам вызов — внутри серверного кода.

Выполнение процедуры на сервере в привилегированном режиме

Бывает, что пользователю нельзя давать права на регистр, но код должен в него записать. Например, служебный журнал операций. Для этого есть привилегированный режим: в нём не проверяются права доступа и ограничения на уровне записей.

Включить его можно двумя способами.

  • 🔐 Флажок Привилегированный у общего модуля. Весь серверный код модуля выполняется без проверки прав. Модуль при этом может быть только серверным.
  • ⚙️ Метод УстановитьПривилегированныйРежим(Истина) внутри серверной процедуры. Режим действует до вызова УстановитьПривилегированныйРежим(Ложь) или до возврата на клиент.
&НаСервереБезКонтекста
Процедура ЗаписатьВЖурналОпераций(Знач Текст)
    УстановитьПривилегированныйРежим(Истина);
    Запись = РегистрыСведений.ЖурналОпераций.СоздатьМенеджерЗаписи();
    Запись.Период = ТекущаяДатаСеанса();
    Запись.Пользователь = Пользователи.ТекущийПользователь();
    Запись.Текст = Текст;
    Запись.Записать();
    УстановитьПривилегированныйРежим(Ложь);
КонецПроцедуры

Регистр ЖурналОпераций условный, а Пользователи.ТекущийПользователь() есть в конфигурациях на Библиотеке стандартных подсистем. На клиенте привилегированный режим не включается: метод работает только на сервере. Проверить текущее состояние можно функцией ПривилегированныйРежим().

Никогда не принимайте в привилегированной процедуре «сырой» текст запроса или имя объекта от клиента. Иначе любой пользователь, вызвав такой метод, прочитает данные, на которые у него нет прав. Привилегированный код должен делать ровно одну заранее известную операцию.

Асинхронный запуск процедуры на сервере: фоновые задания

Серверный вызов из формы синхронный. Пока сервер считает, интерфейс у пользователя стоит. Для операций дольше нескольких секунд — пересчёт, загрузка файла, массовое перепроведение — процедуру запускают фоновым заданием.

Как запустить фоновое задание

Процедура для фона должна быть экспортной и лежать в серверном общем модуле. Результат она кладёт во временное хранилище.

// Общий модуль ДлительныеРасчеты (флажок «Сервер»)
Процедура ПересчитатьЦены(Параметры, АдресРезультата) Экспорт
    Обработано = 0;
    // ... долгий расчёт ...
    ПоместитьВоВременноеХранилище(Обработано, АдресРезультата);
КонецПроцедуры
&НаСервере
Функция ЗапуститьПересчетНаСервере()
    АдресРезультата = ПоместитьВоВременноеХранилище(Неопределено, УникальныйИдентификатор);
    ПараметрыЗадания = Новый Массив;
    ПараметрыЗадания.Добавить(Новый Структура("Склад", Объект.Склад));
    ПараметрыЗадания.Добавить(АдресРезультата);
    Задание = ФоновыеЗадания.Выполнить("ДлительныеРасчеты.ПересчитатьЦены",
        ПараметрыЗадания, , "Пересчёт цен");
    ИдентификаторЗадания = Задание.УникальныйИдентификатор;
    Возврат АдресРезультата;
КонецФункции

Первый аргумент ФоновыеЗадания.Выполнить — строка «ИмяМодуля.ИмяМетода». Второй — массив параметров в порядке объявления. Третий — ключ: два задания с одним ключом одновременно не запустятся, это защищает от двойного нажатия кнопки. Четвёртый — наименование, которое видно в списке заданий.

Временное хранилище создаётся с идентификатором формы. Пока форма открыта, результат не пропадёт.

Как дождаться результата

На клиенте подключите обработчик ожидания и опрашивайте состояние задания:

&НаКлиенте
Процедура ПроверитьЗадание() Экспорт
    Если ЗаданиеЗавершено(ИдентификаторЗадания) Тогда
        Обработано = ПолучитьИзВременногоХранилища(АдресРезультата);
        ПоказатьОповещениеПользователя("Готово", , "Обработано: " + Формат(Обработано, "ЧГ=0; ЧН=0"));
    Иначе
        ПодключитьОбработчикОжидания("ПроверитьЗадание", 2, Истина);
    КонецЕсли;
КонецПроцедуры

&НаСервереБезКонтекста
Функция ЗаданиеЗавершено(Знач Идентификатор)
    Задание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(Идентификатор);
    Возврат Задание = Неопределено Или Задание.Состояние <> СостояниеФоновогоЗадания.Активно;
КонецФункции

ИдентификаторЗадания и АдресРезультата здесь — реквизиты формы. На сервере, если нужно, задание можно ждать синхронно: Задание.ОжидатьЗавершенияВыполнения(30) — ждать не дольше 30 секунд.

В типовых конфигурациях на БСП не пишите опрос вручную. Там есть готовые ДлительныеОперации.ВыполнитьВФоне на сервере и ДлительныеОперацииКлиент.ОжидатьЗавершение на клиенте: они сами показывают индикатор, ловят ошибки и чистят хранилище.

Асинх и Ждать — это не про сервер

С платформы 8.3.18 в клиентском коде появились Асинх и Ждать. Они упрощают работу с диалогами и файлами на клиенте. Серверный вызов от них асинхронным не становится: для долгого кода по-прежнему нужен фон.

Разовый запуск процедуры на сервере без правки конфигурации

Иногда процедуру надо выполнить один раз в рабочей базе: поправить данные, проверить гипотезу, вызвать метод общего модуля. Снимать конфигурацию с поддержки ради этого не нужно.

Внешняя обработка. Создайте в Конфигураторе внешнюю обработку (Файл → Новый → Внешняя обработка), добавьте форму, кнопку и пару процедур: клиентский обработчик и серверную процедуру с вашим кодом. Откройте файл в пользовательском режиме через Файл → Открыть. Серверная часть выполнится в контексте базы с правами текущего пользователя. Запуск внешних обработок требует соответствующего права, а при включённой защите от опасных действий платформа может попросить подтверждение.

Регламентное задание. Если процедура уже оформлена как регламентное задание, его можно запустить вручную. В конфигурациях на БСП это делают в разделе Администрирование → Обслуживание → Регламентные и фоновые задания: выделите задание и выполните его сразу, не дожидаясь расписания. Там же видны активные и завершённые фоновые задания с текстом ошибок.

Код, который меняет данные, сначала прогоните на копии базы. Обработку, которая массово перезаписывает документы, в рабочей базе запускайте, когда пользователи не проводят документы: иначе возможны конфликты блокировок и ошибки у них.

Перед запуском своей процедуры на сервере в рабочей базе
Выполнено: 0 / 6

Отладка и диагностика серверного кода

Отладка в файловом варианте

В файловой базе серверный код выполняется внутри клиентского приложения. Точки останова в процедурах &НаСервере срабатывают сразу: запустите отладку из Конфигуратора клавишей F5, ничего дополнительно настраивать не нужно.

Отладка на сервере 1С

В клиент-серверном варианте рабочий процесс должен разрешать отладку. Для этого агент сервера запускают с ключом -debug. На Windows его дописывают в командную строку службы сервера 1С:Предприятия, затем службу перезапускают. Для отладки по протоколу HTTP добавляют ещё ключ -http, и тот же режим выбирают в Конфигураторе в параметрах отладки.

Перезапуск службы сервера 1С обрывает все сеансы пользователей во всех базах кластера. Делайте это вне рабочего времени или на тестовом сервере. На рабочем кластере отладку постоянно не держат: она снижает производительность.

После перезапуска в Конфигураторе откройте Отладка → Подключение и включите автоматическое подключение серверных предметов отладки. Тогда точки останова в серверных процедурах будут срабатывать, как в файловой базе.

Диагностика без отладчика

Отладчик не всегда доступен: рабочий сервер, нет прав, ошибка плавающая. Тогда помогают другие инструменты.

  • 📋 Журнал регистрации. В серверном коде пишите события методом ЗаписьЖурналаРегистрации("Пересчёт цен", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки()). Смотрят его в Администрирование → Обслуживание → Журнал регистрации или из Конфигуратора.
  • ⏱ Замер производительности. В Конфигураторе Отладка → Замер производительности показывает, какие строки серверного кода съедают время. Здесь же видно лишние серверные вызовы.
  • 🧾 Технологический журнал. Настраивается файлом logcfg.xml на сервере и пишет события рабочих процессов: исключения, длительные запросы, блокировки. Это инструмент для случаев, когда ошибка воспроизводится только у пользователей.
  • 🧩 Попытка / Исключение. Оборачивайте фоновую процедуру целиком и пишите ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()) в журнал: ошибка в фоне не всплывает к пользователю сама.

Почему серверная процедура не вызывается: разбор ошибок

Диагностика: выберите симптом

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

Можно ли вызвать серверную процедуру из обработчика ожидания?
Напрямую нет: обработчик ожидания — клиентская процедура. Но внутри него можно вызвать серверную функцию формы или общего модуля с флажком «Вызов сервера», как из любого клиентского кода.
Сколько параметров можно передать в фоновое задание?
Столько, сколько у процедуры. Их передают массивом в порядке объявления. Если параметров много, удобнее упаковать их в одну структуру.
Выполняются ли фоновые задания в файловой базе?
В файловом варианте 8.3 фоновые задания выполняются, пока открыт хотя бы один сеанс клиентского приложения. Для регламентных заданий по расписанию файловая база подходит хуже, чем клиент-серверная.
Чем &НаКлиентеНаСервереБезКонтекста отличается от общего модуля с флажками Клиент и Сервер?
Директива действует только внутри одного модуля формы. Общий модуль виден всей конфигурации. Если функция нужна в двух и более формах, выносите её в модуль.
Можно ли из серверной процедуры открыть форму или задать вопрос пользователю?
Нет. Диалоги и формы — клиентские методы. Верните с сервера признак или текст, а вопрос задайте в клиентской процедуре после вызова.