При разработке систем интеграции в 1С часто возникает задача: при записи или проведении документа необходимо передать данные во внешнюю систему (например, на сайт, в CRM или через API курьерской службы). Выполнение HTTP-запроса непосредственно в коде обработчика ПриЗаписи — крайне опасная практика. Если внешний сервис будет отвечать медленно, база данных окажется заблокированной на всё время ожидания ответа, что парализует работу пользователей. В этой статье мы подробно разберем, как вынести отправку данных в фоновое задание, какие риски при этом возникают и почему профессионалы часто выбирают промежуточную очередь в регистре сведений.
Рассмотрим самый простой и быстрый с точки зрения разработки подход. Мы вызываем метод платформы ФоновыеЗадания.Выполнить() непосредственно в модуле объекта. Это позволяет основному потоку завершить запись документа, не дожидаясь ответа от внешнего сервера.
Преимущества:
Проанализируем риски этого метода:
Основная проблема заключается в том, что фоновое задание запускается параллельно с продолжающейся транзакцией записи в основной базе. Мы можем столкнуться с ситуацией, когда фоновое задание стартовало, попыталось найти наш документ по ссылке, но не нашло его, так как транзакция в основном потоке еще не завершена (Commit не выполнен). Это называется проблемой "фантомного чтения".
Вторым критическим моментом является риск отката транзакции. Если после вызова метода Выполнить() в коде документа произойдет ошибка (например, сработает Отказ = Истина в другом обработчике), документ не запишется, но фоновое задание уже будет отправлено. В результате внешняя система получит данные о заказе, которого не существует в 1С.
Если в вашей конфигурации используется Библиотека стандартных подсистем (БСП), рекомендуется использовать программный интерфейс модуля ДлительныеОперации. Это упростит жизнь будущим разработчикам, так как этот механизм стандартизирован.
Разберем пример кода для запуска процедуры в фоне:
ПараметрыПроцедуры = Новый Структура;
ПараметрыПроцедуры.Вставить("Ссылка", Ссылка);
ПараметрыПроцедуры.Вставить("ДанныеДляОтправки", СтруктураДанных);
Результат = ДлительныеОперации.ВыполнитьПроцедуру(
Неопределено,
"МойОбщийМодульИнтеграция.ОтправитьДанныеВФоне",
ПараметрыПроцедуры
);
Для удобства отладки полезно предусмотреть механизм, позволяющий выполнять код синхронно, если включен режим отладки. Рассмотрим, как это упростит поиск ошибок:
Если ОбщегоНазначения.РежимОтладки() Тогда
// В режиме отладки выполняем синхронно, чтобы видеть ошибки в текущем сеансе
МойОбщийМодульИнтеграция.ОтправитьДанныеВФоне(ПараметрыПроцедуры);
Иначе
// В рабочем режиме - только через фон
ФоновыеЗадания.Выполнить("МойОбщийМодульИнтеграция.ОтправитьДанныеВФоне", ПараметрыПроцедуры);
КонецЕсли;
Для высоконагруженных систем или процессов, где потеря данных недопустима, мы рекомендуем использовать архитектурный шаблон "Очередь сообщений" на базе независимого регистра сведений. Разберем по шагам, как это работает:
ПриЗаписи документа мы создаем запись в специальном регистре сведений (например, ОчередьИнтеграции). Эта запись создается внутри транзакции. Если запись документа сорвется, запись в регистре тоже не появится.Проанализируем преимущества такого подхода:
КоличествоПопыток и ТекстОшибки. Это позволит администратору видеть, какие сообщения "зависли" и по какой причине.Пример структуры кода для обработки такой очереди:
Процедура ОбработатьОчередьОтправки() Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 50
| ОчередьИнтеграции.Объект КАК Объект,
| ОчередьИнтеграции.Параметры КАК Параметры
|ИЗ
| РегистрСведений.ОчередьИнтеграции КАК ОчередьИнтеграции
|УПОРЯДОЧИТЬ ПО
| ОчередьИнтеграции.МоментВремени ВОЗР";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Попытка
ОтправитьЗапросНаВнешнийСервис(Выборка.Объект, Выборка.Параметры);
// Если успешно - удаляем из очереди
УдалитьИзОчереди(Выборка.Объект);
Исключение
// Фиксируем ошибку и увеличиваем счетчик попыток
ЗаписатьОшибкуВРегистр(Выборка.Объект, ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Выясним причины, по которым фоновые задания могут не срабатывать или вызывать ошибки платформы:
Сериализация параметров: При вызове ФоновыеЗадания.Выполнить() все параметры, которые вы передаете (например, структура или массив), должны быть сериализуемыми. Нельзя передавать сам объект документа ДокументОбъект, так как он является мутабельным значением. Передавайте только Ссылку, примитивные типы (Строка, Число) или ХранилищеЗначения.
Контекст выполнения: Фоновое задание выполняется в отдельном сеансе на сервере. Это означает, что у него нет доступа к клиентскому контексту (открытые формы, временные файлы на компьютере пользователя). Все необходимые данные должны быть либо в базе, либо переданы в параметрах.
Лицензирование: Помните, что каждое активно работающее фоновое задание может занимать клиентскую лицензию (в зависимости от настроек сервера и версии платформы). При массовой записи документов запуск сотни фоновых заданий может привести к временному исчерпанию пула лицензий.
Подведем итог нашему анализу:
Попытка...Исключение внутри кода фонового задания, чтобы ошибки внешней системы не приводили к аварийному завершению рабочих процессов сервера.