При интеграции внешнего оборудования (например, RFID-считывателей, сканеров штрихкодов или весовых терминалов) разработчики часто сталкиваются со следующей архитектурной проблемой: устройство успешно передает данные в опубликованный веб-сервис 1С, но эти данные обрабатываются в фоновом сеансе на сервере. Как теперь оперативно «пробросить» эту информацию на экран конкретного пользователя, у которого в данный момент открыта определенная форма? Ведь протокол HTTP работает по принципу «запрос-ответ», и сервер не может по своей инициативе напрямую вызвать клиентский метод без подготовленного канала связи.
В этой статье мы подробно разберем несколько вариантов решения этой задачи — от простых «костылей» до современных штатных механизмов платформы 1С и использования внешних компонент.
Начиная с версии платформы 1С 8.3.26, разработчикам доступен долгожданный встроенный инструмент для отправки push-уведомлений с сервера на клиент без использования Системы взаимодействия — МенеджерУведомленийКлиента. Этот механизм идеально подходит для решения нашей задачи.
Рассмотрим по шагам, как настроить эту связку:
Разберем пример реализации клиентской части в модуле управляемой формы:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Подписываемся на событие получения данных RFID
УведомленияКлиента.ПодключитьОбработчик("СобытиеСчитыванияRFID", "ОбработатьДанныеRFID");
КонецПроцедуры
&НаКлиенте
Процедура ПриЗакрытии(ЗавершениеРаботы)
// Отключаем обработчик при закрытии формы
УведомленияКлиента.ОтключитьОбработчик("СобытиеСчитыванияRFID", "ОбработатьДанныеRFID");
КонецПроцедуры
&НаКлиенте
Процедура ОбработатьДанныеRFID(ИмяСобытия, ПараметрыСобытия) Экспорт
Если ИмяСобытия = "СобытиеСчитыванияRFID" Тогда
// Обрабатываем полученную структуру данных
КодМетки = ПараметрыСобытия.КодМетки;
Сообщить("Успешно считана RFID-метка на клиенте: " + КодМетки);
КонецЕсли;
КонецПроцедуры
Теперь посмотрим, как выглядит отправка сообщения из серверного метода нашего веб-сервиса:
Функция ОбработатьЗапросОтСчитывателя(ДанныеМетки, ИмяПользователяПолучателя) Экспорт
// Формируем параметры события для отправки на клиент
ПараметрыСобытия = Новый Структура;
ПараметрыСобытия.Вставить("КодМетки", ДанныеМетки);
// Определяем активный сеанс нужного пользователя
МассивСеансов = Новый Массив;
СоединенияИнформационнойБазы = ПолучитьСоединенияИнформационнойБазы();
Для Каждого Соединение Из СоединенияИнформационнойБазы Цикл
Если Соединение.ИмяПользователя = ИмяПользователяПолучателя Тогда
МассивСеансов.Добавить(Соединение.НомерСеанса);
КонецЕсли;
КонецЦикла;
// Если сеанс найден, отправляем push-уведомление
Если МассивСеансов.Количество() > 0 Тогда
УведомленияКлиента.ОтправитьУведомление("СобытиеСчитыванияRFID", ПараметрыСобытия, МассивСеансов);
КонецЕсли;
КонецФункции
Преимущества метода: Работает полностью на уровне платформы, не создает холостой нагрузки на СУБД, гарантирует мгновенную доставку (миллисекунды) непосредственно в конкретный сеанс пользователя.
Если ваша конфигурация работает на более ранних версиях платформы 8.3, то лучшей альтернативой является Система взаимодействия. Она позволяет серверу инициировать выполнение кода на клиенте через механизм интеграции.
Рассмотрим логику реализации:
Этот метод требует развертывания локального сервера Системы взаимодействия (или использования облачного сервиса 1С) и настройки интеграции, что может усложнить администрирование системы.
Самый простой в реализации и классический «обходной путь», который не требует сторонних систем и работает на абсолютно любой версии платформы 1С. Суть метода заключается в том, что клиентская форма сама регулярно (например, раз в 1-2 секунды) «спрашивает» у сервера, появились ли для нее новые данные.
Чтобы минимизировать нагрузку на систему при таком подходе, спроектируем легкую схему:
ОчередьСобытийОборудования с измерениями ИдентификаторСеанса (УникальныйИдентификатор) или Пользователь, и ресурсами ДанныеСобытия (Строка/ХранилищеЗначения) и Обработано (Булево).ПодключитьОбработчикОжидания().Разберем пример кода для оптимизированного опроса:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Регистрируем наш уникальный идентификатор формы на сервере
ИдентификаторФормы = Новый УникальныйИдентификатор;
// Подключаем опрос раз в 1.5 секунды
ПодключитьОбработчикОжидания("ПроверитьВходящиеСобытия", 1.5);
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьВходящиеСобытия()
// Вызываем облегченный неконтекстный серверный метод
ДанныеRFID = ПроверитьСобытияНаСервере(ИдентификаторФормы);
Если ЗначениеЗаполнено(ДанныеRFID) Тогда
// Обрабатываем данные на форме
Сообщить("Получены данные через пулинг: " + ДанныеRFID);
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПроверитьСобытияНаСервере(ИдентификаторФормы)
УстановитьПривилегированныйРежим(Истина);
ДанныеRFID = "";
// Ищем необработанные записи для конкретной формы
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Очередь.ДанныеСобытия КАК ДанныеСобытия,
| Очередь.Период КАК Период
|ИЗ
| РегистрСведений.ОчередьСобытийОборудования КАК Очередь
|ГДЕ
| Очередь.ИдентификаторФормы = &ИдентификаторФормы
| И НЕ Очередь.Обработано";
Запрос.УстановитьПараметр("ИдентификаторФормы", ИдентификаторФормы);
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Выборка = Результат.Выбрать() Тогда
Выборка.Следующий();
ДанныеRFID = Выборка.ДанныеСобытия;
// Помечаем событие как обработанное или удаляем запись
МенеджерЗаписи = РегистрыСведений.ОчередьСобытийОборудования.СоздатьМенеджерЗаписи();
МенеджерЗаписи.ИдентификаторФормы = ИдентификаторФормы;
МенеджерЗаписи.Период = Выборка.Период;
МенеджерЗаписи.Прочитать();
Если МенеджерЗаписи.Выбран() Тогда
МенеджерЗаписи.Обработано = Истина;
МенеджерЗаписи.Записать();
КонецЕсли;
КонецЕсли;
Возврат ДанныеRFID;
КонецФункции
Важное предупреждение: При использовании этого метода критически важно вызывать серверные процедуры с директивой &НаСервереБезКонтекста. Это убережет систему от постоянной передачи тяжелого контекста формы туда и обратно. Тем не менее, если количество одновременно работающих пользователей превышает 15–20 человек, постоянный опрос базы данных создаст заметную паразитную нагрузку на СУБД и процессор сервера приложений.
Для создания полноценного асинхронного сценария по типу стандартного сканера штрихкодов ("ВнешнееСобытие") часто используют внешние компоненты.
Схема взаимодействия выглядит следующим образом:
ВнешнееСобытие().Для реализации этого метода в модуле формы прописывается стандартный обработчик:
&НаКлиенте
Процедура ВнешнееСобытие(Источник, Событие, Данные)
Если Источник = "ЛокальныйRFIDАгент" И Событие = "СчитываниеМетки" Тогда
Сообщить("Событие от внешней компоненты! Код метки: " + Данные);
// Выполняем полезную работу
КонецЕсли;
КонецПроцедуры
Преимущества метода: Полное отсутствие нагрузки на сервер 1С. Мгновенная реакция интерфейса. Решение работает локально и автономно.
Недостатки: Требуется разработка или покупка стабильной внешней компоненты, а также индивидуальная настройка сетевых доступов (маршрутизации портов) между RFID-оборудованием и компьютерами пользователей.
Для правильного выбора архитектуры проанализируем масштаб вашей задачи: