При интеграции 1С с внешними сайтами или CRM-системами часто возникает задача оперативной передачи данных об изменении статусов заказов. Одной из популярных методик является использование подписки на событие ПриЗаписи регистра сведений, например, СостоянияЗаказовКлиентов в УТ 11.4. Однако на практике разработчики сталкиваются с серьезной проблемой: внешняя система получает уведомление с Уникальным Идентификатором (УИД) объекта, но при попытке найти этот объект в базе 1С выясняется, что его не существует.
В этой статье мы подробно разберем, почему возникают «фантомные» записи, какие риски несет текущий подход и как спроектировать надежную систему оповещений.
Разберем ситуацию: в конфигурации создана подписка на событие ПриЗаписи для набора записей регистра. Внутри обработчика выполняется HTTP-запрос к API сайта. Посмотрим на фрагмент кода, который вызывает проблему:
сЗаказы = Новый Структура;
сЗаказы.Вставить("code", Источник.Отбор.Заказ.Значение.Номер);
сЗаказы.Вставить("uid", Строка(Источник.Отбор.Заказ.Значение.Ссылка.УникальныйИдентификатор));
// ... формирование JSON ...
Результат = apv_МодульСайт.ВыполнитьAPI(API, СтрокаJSON, Токен);
Выясним причину ошибки: Событие ПриЗаписи регистра сведений всегда выполняется внутри транзакции записи основного объекта (документа или самого набора записей). В 1С транзакция работает по принципу «все или ничего».
ЗаказКлиента.СостоянияЗаказовКлиентов.Отказ = Истина, транзакция отменяется (Rollback).В результате данные в базе 1С не сохраняются, но внешняя система уже получила уведомление. УИД, который был отправлен, фактически никогда не был зафиксирован в базе данных, поэтому найти такой документ позже невозможно.
Помимо проблемы с транзакциями, выполнение вызовов API (ВыполнитьAPI) напрямую в подписках несет в себе огромные риски для стабильности системы:
Это наиболее сбалансированный метод, реализующий паттерн Transactional Outbox. Разберем его по шагам:
apv_ОчередьУведомлений с измерениями Объект и реквизитами для хранения данных (например, тип события, дата постановки в очередь).ПриЗаписи вместо отправки запроса на сайт будем просто записывать новую строку в этот регистр.Посмотрим, как изменится логика. Поскольку запись в вспомогательный регистр происходит в той же транзакции, что и основной документ, то при отмене транзакции запись в очередь также исчезнет. Это гарантирует, что мы отправим данные только о реально созданных объектах.
Для обработки очереди создадим регламентное задание, которое будет запускаться раз в 1-5 минут:
Процедура ОтправитьУведомленияИзОчереди() Экспорт
Запрос = Новый Запрос("ВЫБРАТЬ Объект ИЗ РегистрСведений.apv_ОчередьУведомлений");
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Попытка
// Здесь выполняем реальный HTTP-запрос
Если apv_МодульСайт.ОтправитьДанныеНаСайт(Выборка.Объект) Тогда
// При успехе удаляем из очереди
Набор = РегистрыСведений.apv_ОчередьУведомлений.СоздатьНаборЗаписей();
Набор.Отбор.Объект.Установить(Выборка.Объект);
Набор.Записать();
КонецЕсли;
Исключение
// Логируем ошибку, запись остается в очереди для повтора
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Планы обмена — это встроенный в 1С механизм отслеживания изменений, который идеально подходит для нашей задачи. Проанализируем преимущества этого подхода:
Для реализации создаем ПланОбмена, добавляем в его состав документ ЗаказКлиента или регистр СостоянияЗаказовКлиентов. В регламентном задании используем метод ПланыОбмена.ВыбратьИзменения(), отправляем данные на сайт и вызываем ПланыОбмена.УдалитьРегистрациюИзменений() после успешного ответа API.
Если бизнес-требования диктуют необходимость «моментальной» передачи данных (быстрее, чем работает регламентное задание), можно использовать фоновые задания. Однако здесь есть важный нюанс.
Рассмотрим пример запуска фонового задания из подписки:
ПараметрыЗадания = Новый Структура("Объект", Источник.Отбор.Заказ.Значение);
ФоновыеЗадания.Выполнить("apv_МодульСайт.ФоноваяОтправка", ПараметрыЗадания);
Важное предупреждение: Фоновое задание может стартовать параллельно с основной транзакцией и попытаться прочитать объект еще до того, как он будет окончательно зафиксирован (Commit) в базе данных. В этом случае фоновое задание не увидит документ. Чтобы этого избежать, внутри фонового задания рекомендуется реализовать «мягкое ожидание» — цикл из 3-5 попыток чтения объекта с паузой в 1 секунду между ними.
Проанализировав ситуацию, мы пришли к следующим выводам:
СостоянияЗаказовКлиентов: он может обновляться фоновыми процессами УТ 11 (например, при расчете просрочки оплаты). Проверяйте, действительно ли состояние изменилось, прежде чем спамить CRM уведомлениями.Использование очереди сообщений или планов обмена позволит вам гарантировать целостность данных и высокую скорость работы пользователей в 1С, независимо от доступности внешнего сайта.