Рассмотрим достаточно распространенную ситуацию, с которой сталкиваются разработчики и администраторы баз данных 1С. При выполнении штатного обмена данными между конфигурациями, например, из «Розницы» в «Управление торговлей» (УТ), процесс внезапно прерывается, и в журнале регистрации фиксируются странные ошибки. Текст ошибок выглядит примерно так:
{ОбщийМодуль.INT_Сервисный.Модуль(418,10)}: Процедура или функция с указанным именем не определена (ПолучитьСерверТО)
Если Не ПолучитьСерверТО().ОтключитьОбработкиОбслуживания() Тогда
{ОбщийМодуль.INT_Сервисный.Модуль(569,5)}: Процедура или функция с указанным именем не определена (Предупреждение)
Предупреждение("Выбранный файл не является внешней обработкой.");
Разберем эту ситуацию по шагам. На первый взгляд кажется нелогичным, что обмен данными, который должен работать в фоне, затрагивает участки кода, связанные с торговым оборудованием или выводом интерактивных сообщений на экран. Более того, пользователи могут начать жаловаться на зависание программы — сессии 5-10 человек могут просто остановиться. Проанализируем, почему так происходит и как грамотно устранить эту проблему.
Главная причина кроется в архитектуре платформы 1С:Предприятие, а именно в строгом разделении на клиентский и серверный контексты. Ошибки вида Процедура или функция с указанным именем не определена для методов ПолучитьСерверТО и Предупреждение означают, что система пытается скомпилировать или выполнить этот код там, где эти функции физически отсутствуют.
Посмотрим на эти функции внимательнее:
Обе эти функции существуют исключительного на стороне клиента. Однако обмен данными (загрузка и выгрузка) обычно выполняется с помощью регламентных фоновых заданий, то есть на сервере, либо через внешнее COM-соединение. В этих контекстах нет графического интерфейса, нет подключенного локального оборудования и некому нажимать кнопки в окнах. Когда сервер или внешнее соединение пытается прочитать общий модуль, в котором стоит галочка «Сервер» или «Внешнее соединение», и натыкается на этот код, происходит критическая ошибка компиляции.
Выясним причину, по которой проблема не ограничивается только падением обмена, но и приводит к зависанию рабочих сеансов других пользователей. Это классическое следствие вызова интерактивных методов в фоновом режиме.
Если код написан таким образом, что вызов метода Предупреждение (или подобных ему, например, Вопрос) все-таки начинает выполняться на сервере или в COM-соединении, процесс «повисает». Программа открывает невидимое диалоговое окно в памяти сервера и бесконечно ждет, пока кто-нибудь нажмет в нем кнопку. Так как физически этого никто сделать не может, фоновое задание обмена блокируется на неопределенный срок.
При этом, процесс обмена данными работает внутри транзакции. Он удерживает блокировки на таблицах базы данных (на справочниках, документах, регистрах), в которые пытался записать данные. Сеансы обычных пользователей, которые в этот момент пытаются открыть, провести или сохранить те же самые объекты, натыкаются на эти транзакционные блокировки и закономерно зависают, ожидая ответа от сервера.
Рассмотрим частый аргумент: «Мы ничего не меняли в конфигурации, раньше все работало». Код действительно мог оставаться нетронутым, но изменились условия вызова этого кода. Посмотрим на возможные причины:
ОбработкаПроведения, которая, следуя логике, обратилась к общему модулю и вызвала проблемную функцию.Давайте разберем по шагам, как выявить и устранить подобные архитектурные ошибки в конфигурации.
Для начала нам нужно найти все подобные ошибки. Не стоит ждать очередного падения обмена. Выполним проверку вручную:
Система выдаст вам полный список мест, где клиентские функции вызываются в серверном контексте. Именно здесь и кроется проблема.
Если мы нашли в общем модуле (например, INT_Сервисный) процедуры, которые нужны и на клиенте, и на сервере, но внутри них есть обращения к торговому оборудованию, мы должны изолировать этот код.
Рассмотрим пример того, как нужно оборачивать клиентский код инструкциями препроцессора, чтобы сервер игнорировал его при компиляции:
Процедура КнопкаНажатиеОбработкаТерминалРозничной() Экспорт
// Оборачиваем клиентский код в директиву
#Если Клиент Тогда
Если Не ПолучитьСерверТО().ОтключитьОбработкиОбслуживания() Тогда
Возврат;
КонецЕсли;
// Интерактивные сообщения тоже должны быть только на клиенте
Предупреждение("Операция выполнена");
#КонецЕсли
// Далее идет код, который может выполняться на сервере...
КонецПроцедуры
Использование директивы #Если Клиент Тогда ... #КонецЕсли (или #Если Не ВнешнееСоединение И Не Сервер Тогда) укажет платформе, что данный фрагмент кода нужно компилировать только на рабочих местах пользователей.
Хорошим тоном в разработке на платформе 1С является разделение общих модулей по контексту их выполнения. Проанализируем свойства проблемного модуля. Если в модуле установлены одновременно флажки «Клиент (управляемое приложение)», «Сервер» и «Внешнее соединение», риск возникновения таких ошибок возрастает в разы.
Рекомендуется вынести все процедуры работы с оборудованием и интерфейсом в отдельный модуль, например INT_СервисныйКлиент, и оставить галочку только на клиенте. Серверные процедуры оставить в INT_СервисныйВызовСервера. Это исключит проблему на корню.
Если вы исправили код, но сеансы продолжают висеть, значит, старые фоновые задания все еще активны в памяти сервера 1С. Выполним следующие действия:
Внедрение этих исправлений позволит вам навсегда избавиться от внезапных падений обмена по причине контекстных ошибок и обеспечит стабильную работу всех пользователей в информационной базе.