Гарантирует ли платформа 1С хронологическую последовательность документов по GUID внутри одной секунды и как ее обеспечить?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Почему порядок GUID не совпадает с реальным временем создания документов

Разберем внутренний механизм генерации ссылок платформой. 1С формирует идентификаторы документов на базе стандарта UUID v1, который базируется на метке времени и MAC-адресе сетевой карты. Однако порядок байтов, в котором платформа сохраняет ссылку в таблицах СУБД (поле _IDRRef), отличается от текстового представления GUID:

  1. Байты 0–1 хранят так называемую последовательность тактов (clock_seq).
  2. Байты 2–7 хранят идентификатор узла или MAC-адрес (node).
  3. Байты 8–15 хранят метку времени (time_hi, time_mid, time_low).

В СУБД (например, Microsoft SQL Server или PostgreSQL) сравнение бинарных полей binary(16) выполняется слева направо. Это означает, что база данных сначала сравнивает первые байты, отвечающие за clock_seq. До временной метки сравнение доходит только в том случае, если начальные блоки полностью совпали.

Посмотрим на практический пример из обсуждения. Документ, созданный раньше, получил GUID 2600c52a-12eb-11e7-b318-005056a1008a (бинарно: 0xb318005056a1008a11e712eb2600c52a), а документ, созданный позже — 067bb7a4-19c0-11e7-ae82-005056a1008a (бинарно: 0xae82005056a1008a11e719c0067bb7a4). Так как значение 0xae82 меньше 0xb318, более поздний документ с точки зрения базы данных оказывается строго меньше раннего.

Влияние веб-сервисов и сеансов на генерацию идентификаторов

Проанализируем, почему значение clock_seq регулярно изменяется. Значение тактов генерируется рабочим процессом сервера 1С (rphost). Серии непрерывно возрастающих идентификаторов гарантируются только внутри одного сеанса и одного рабочего потока на протяжении короткого периода времени.

Рассмотрим тест генерации ссылок в цикле:


Для инд = 1 По 100 Цикл
    Спр = Справочники.Номенклатура.СоздатьЭлемент();
    Спр.Записать();
    Сообщить(XMLСтрока(Спр.Ссылка));
КонецЦикла;

При выполнении этого кода можно заметить, что через определенные интервалы серия ссылок меняется, и в начале нового блока чисел младшие разряды снова сбрасываются. При вызовах веб-сервисов каждый входящий HTTP- или SOAP-запрос может обрабатываться в отдельном сеансе или даже разными процессами кластера rphost. В таком сценарии надеяться на совпадение физического времени создания и бинарного порядка ссылок категорически нельзя.

Ограничения объектов МоментВремени и Граница

Объекты МоментВремени и Граница предназначены не для восстановления хронологии реального мира, а для детерминированности расчетов платформы. Они гарантируют, что если два документа уже записаны в базу данных, то порядок их взаимного расположения на оси времени будет постоянным и не изменится при повторных выборках или пересчете итогов.

Если два документа одного вида имеют одинаковую секунду, виртуальная таблица СрезПоследних подчиненного регистра сведений будет определять «последний» документ исключительно по сравнению ссылок в бинарном представлении СУБД. Никаких встроенных настроек для изменения логики работы СрезПоследних платформа не предоставляет.

Способ 1. Программный сдвиг даты документа при записи

Самое простое и надежное решение для документов одной цепочки — исключить их попадание в одну и ту же секунду. При обработке входящего вызова веб-сервиса проверяем дату последнего созданного документа в базе. Если входящий документ создается с тем же временем, увеличиваем его реквизит Дата на 1 секунду вперед относительно предыдущего.

Такой подход полностью устраняет зависимость от внутреннего формата GUID, и объект МоментВремени всегда выстраивает документы в правильном порядке.

Способ 2. Добавление собственного счетчика последовательности

Если искусственно изменять дату запрещено бизнес-логикой, необходимо отказаться от использования ссылки как критерия упорядочивания. Реализуем собственный механизм определения актуальности записей:

  1. Добавим в регистр сведений или в шапку документа числовой реквизит-счетчик (например, НомерПакета или НомерОперации), передаваемый из внешней учетной системы.
  2. Вместо обращения к виртуальной таблице СрезПоследних напишем прямой запрос к реальной таблице регистра сведений.
  3. Найдем максимальное значение числового счетчика с помощью группировки или соединения по максимальному номеру.

Посмотрим на пример запроса для получения актуальной записи по максимальному номеру операции:


ВЫБРАТЬ
    Регистр.Объект КАК Объект,
    МАКСИМУМ(Регистр.НомерОперации) КАК МаксНомер
ПОМЕСТИТЬ ВТ_МаксимальныеНомера
ИЗ
    РегистрСведений.СтатусыОбъектов КАК Регистр
СГРУППИРОВАТЬ ПО
    Регистр.Объект
;

ВЫБРАТЬ
    Регистр.Объект,
    Регистр.Статус,
    Регистр.НомерОперации
ИЗ
    РегистрСведений.СтатусыОбъектов КАК Регистр
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_МаксимальныеНомера КАК ВТ
        ПО Регистр.Объект = ВТ.Объект
        И Регистр.НомерОперации = ВТ.МаксНомер

Способ 3. Переход на независимый регистр сведений

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

Способ 4. Организация очереди обработки пакетов

При параллельных вызовах веб-сервисов два запроса могут выполняться одновременно в параллельных потоках, что создает состояние гонки. Чтобы входящие данные выстраивались в правильную цепочку, разделим прием сообщений и их обработку:

  1. Веб-сервис только принимает пакет данных и сохраняет его в таблицу входящих сообщений с отметкой точного времени или сквозным номером входящего пакета.
  2. Проведение документов и формирование движений выполняются регламентным заданием строго последовательно в рамках одного сеанса.

Вывод: Ссылка документа и значение GUID в платформе 1С не предназначены для отслеживания хронологии создания объектов. Попытка влиять на нее через метод УстановитьСсылкуНового нестабильна при перезапуске кластера серверов и распределенных базах. Корректным архитектурным решением является разнесение документов по секундам либо ведение собственного числового нумератора последовательности.

← На главную