Как исправить ошибку MERC56620 при отправке производственных транзакций в Меркурий (ВетИС)?

Программист 1С v8.3 (Управляемые формы) Промышленность, строительство и АПК
← На главную

При интенсивном обмене данными с государственной системой «Меркурий» (ВетИС.API) разработчики и администраторы 1С часто сталкиваются с ошибкой блокировки транзакций на стороне веб-шлюза. Наиболее распространенной и критичной из них является ошибка с кодом MERC56620.

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

Почему возникает ошибка MERC56620?

Для того чтобы понять природу этой ошибки, проанализируем внутреннее устройство складского журнала и транзакционной системы ВетИС. Ошибка MERC56620 по своей сути аналогична взаимоблокировке (deadlock) или таймауту ожидания блокировки в СУБД. Она возникает на стороне серверов Россельхознадзора, когда несколько параллельных запросов пытаются одновременно изменить или использовать одну и ту же сущность. Источником проблемы могут выступать два сценария:

  1. Параллельное списание с одной записи складского журнала: Когда несколько фоновых заданий в 1С одновременно отправляют транспортные или производственные транзакции, которые списывают сырье с одного и того же GUID складской записи (stock entry GUID). Система ВетИС блокирует эту запись для проведения первой операции, а все последующие параллельные транзакции выстраиваются в очередь ожидания. Если время ожидания превышает установленный лимит шлюза, возвращается ошибка MERC56620.
  2. Параллельная работа с незавершенным производством (НЗП): При использовании механизма незавершенного производства, когда в рамках одной активной производственной транзакции параллельно регистрируются новые технологические операции (выпуск продукции или списание сырья), шлюз ВетИС.API не справляется с одновременным доступом к заголовку транзакции НЗП.

Особо остро эта проблема проявляется на предприятиях, практикующих «производство под реализацию», когда на каждую расходную накладную (реализацию) в системе оформляется индивидуальная микро-партия производства. Это создает колоссальную избыточную нагрузку на шлюз ВетИС.API.

Метод 1. Переход на последовательную отправку (Однопоточная очередь)

Если специфика вашего учета требует работы с одними и теми же записями складского журнала или в рамках единого незавершенного производства, главным правилом должно стать исключение параллелизма. Необходимо переписать логику отправки пакетов в Меркурий так, чтобы документы уходили строго последовательно.

Рассмотрим, как реализовать простейший механизм очереди отправки сообщений ВетИС с использованием объектных блокировок в 1С. Вместо мгновенного запуска фонового задания на отправку при проведении документа, мы будем помещать задачу в специальный регистр сведений «ОчередьОбменаМеркурий» и обрабатывать его последовательно.


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

Такой подход гарантирует, что даже если пользователи одновременно создадут 100 документов производства, использующих сырье с одной партии, они будут обработаны строго друг за другом, исключая конкуренцию на сервере Меркурия.

Метод 2. Укрупнение производственных транзакций

Создание отдельного производственного транзита под каждую реализацию — это архитектурная ошибка, которая приводит к лавинообразному увеличению количества запросов к шлюзу ВетИС. Вместо этого рекомендуется перейти к стратегии агрегации.

Рассмотрим подробнее этот процесс:

Важное ограничение: Не стоит объединять слишком много позиций в один документ (более 500-1000 строк), так как это может вызвать другую ошибку — превышение максимального объема XML-пакета или таймаут обработки на стороне веб-сервиса Меркурия. Экспериментально подберите оптимальный размер пакета для вашей информационной базы (обычно в пределах 100-200 строк выпуска в одной транзакции).

Метод 3. Программная обработка ошибки и механизм повторных попыток (Retry)

Поскольку ошибка MERC56620 носит временный характер (транзакция освобождается, как только конкурирующий процесс завершает свою работу), самым простым и действенным способом борьбы «в моменте» является добавление интеллектуального автоповтора при отправке.

Проанализируем пример кода 1С, который перехватывает ошибку блокировки ВетИС, приостанавливает поток выполнения на несколько секунд и повторяет попытку отправки до 5 раз перед тем, как окончательно зафиксировать сбой.


Функция ОтправитьЗапросСАвтоповтором(ДанныеЗапроса, ПараметрыПодключения)
    
    МаксимальноеКоличествоПопыток = 5;
    ИнтервалПаузы = 2; // Пауза в секундах перед повтором
    ТекущаяПопытка = 1;
    Успешно = Ложь;
    ОтветШлюза = Неопределено;
    
    Пока ТекущаяПопытка <= МаксимальноеКоличествоПопыток И НЕ Успешно Цикл
        
        Попытка
            ОтветШлюза = ВыполнитьЗапросКШлюзу(ДанныеЗапроса, ПараметрыПодключения);
            Успешно = Истина;
        Исключение
            ИнформацияОбОшибке = ИнформацияОбОшибке();
            ТекстОшибки = КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
            
            // Проверяем, содержит ли текст ответа код ошибки MERC56620
            Если Найти(ТекстОшибки, "MERC56620") > 0 Тогда
                ЗаписьЖурналаРегистрации("ВетИС.Интеграция",
                    УровеньЖурналаРегистрации.Предупреждение, , ,
                    "Обнаружена блокировка MERC56620. Попытка " + Строка(ТекущаяПопытка) + " из " + Строка(МаксимальноеКоличествоПопыток));
                
                // Делаем паузу перед следующей попыткой
                СигналПаузы(ИнтервалПаузы);
                ТекущаяПопытка = ТекущаяПопытка + 1;
            Иначе
                // Если ошибка другая, прерываем цикл автоповторов
                ВызватьИсключение ТекстОшибки;
            КонецЕсли;
        КонецПопытки;
        
    КонецЦикла;
    
    Если НЕ Успешно Тогда
        ВызватьИсключение "Не удалось отправить транзакцию в Меркурий из-за постоянных блокировок на сервере ВетИС.";
    КонецЕсли;
    
    Возврат ОтветШлюза;
    
КонецФункции

Процедура СигналПаузы(Секунды)
    // Реализация паузы без загрузки процессора
    ПодключитьОбработчикОжидания("ПустаяПроцедура", Секунды, Истина);
    // Для фоновых заданий можно использовать альтернативный метод:
    // Систематизированное ожидание через вызов Windows API или метод глобального контекста Предупреждение с таймаутом (на клиенте)
    // Либо через выполнение блокирующего вызова к системным утилитам ping/timeout на сервере:
    КомандаСистемы("timeout /t " + Строка(Секунды) + " /nobreak", Ложь);
КонецПроцедуры

Резюме и рекомендации

Для полного устранения ошибки MERC56620 на высоконагруженных предприятиях рекомендуется применить комплексный подход:

  1. Провести аудит вашей системы обмена с ВетИС и уйти от практики «один чек/накладная = одна транзакция производства». Объединяйте выпуски.
  2. Для процессов отправки незавершенного производства (НЗП) настроить строгую очередность в один поток в рамках одного производственного GUID.
  3. Обязательно внедрить в код интеграционного модуля обработчик ошибок с распознаванием кода MERC56620 и автоматическим повторением запроса через небольшую паузу.
← На главную