При автоматической записи справочников или документов (например, через регламентные задания или фоновые процессы интеграции) разработчики и системные администраторы нередко сталкиваются с ошибкой «Код не уникален» или «Номер не уникален». В некоторых инфраструктурах эта неполадка временно исчезает после перезапуска службы ragent (Агент сервера 1С:Предприятия), но затем проявляется снова. Разберем подробнее внутреннее устройство механизма автонумерации, выясним фундаментальные причины сбоя и рассмотрим правильные способы устранения проблемы.
Для обеспечения высокого быстродействия платформа 1С не выполняет запрос к базе данных СУБД за новым номером при каждом создании объекта. Вместо этого генерацией кодов и номеров управляет специальный внутренний сервис нумерации, работающий в оперативной памяти менеджера кластера серверов 1С (rmngr).
Проанализируем ключевые особенности работы этого механизма:
Наиболее опасной архитектурной ошибкой является ситуация, когда два независимых кластера серверов 1С (например, основной сервер и сервер для обменов/фоновых задач) настроены на работу с одной и той же информационной базой в SQL Server. В этом случае каждый кластер выделяет свой собственный независимый пул номеров в ОЗУ и ничего не знает о действиях соседнего менеджера. Рано или поздно оба кластера пытаются выдать один и тот же код разным объектам, что приводит к гарантированному сбою уникальности.
Помимо нарушения нумерации, одновременная работа нескольких кластеров с единой СУБД несет критические риски разрушения данных:
Единственно правильным архитектурным решением является объединение всех физических серверов 1С в один общий кластер. В рамках одного кластера работает централизованный сервис нумерации и единый менеджер блокировок.
Разберем по шагам, как распределить нагрузку внутри единого кластера:
Если серверная архитектура настроена верно, но автонумератор сбился из-за некорректно введенного вручную номера или сбоя транзакции, используем платформенный метод ОбновитьНумерациюОбъектов(). Этот метод принудительно очищает кэш в памяти сервера и заново вычисляет максимальный номер непосредственно из таблиц базы данных.
Посмотрим на пример точечного обновления нумерации без блокировки всей базы данных:
// Обновление нумерации для конкретного справочника
ОбновитьНумерациюОбъектов(Метаданные.Справочники.Номенклатура);
// Обновление нумерации для конкретного документа
ОбновитьНумерациюОбъектов(Метаданные.Документы.РеализацияТоваровУслуг);
// Обновление нумерации для массива объектов метаданных
МассивОбъектов = Новый Массив;
МассивОбъектов.Добавить(Метаданные.Справочники.Контрагенты);
МассивОбъектов.Добавить(Метаданные.Справочники.ДоговорыКонтрагентов);
ОбновитьНумерациюОбъектов(МассивОбъектов);
Вызов метода ОбновитьНумерациюОбъектов() без параметров выполняет пересчет абсолютно для всех объектов метаданных конфигурации, что может вызвать временные задержки на высоконагруженных базах. Поэтому всегда рекомендуется передавать конкретный объект или массив объектов метаданных.
При программном создании и записи элементов через регламентные задания, внешние подключения или веб-сервисы рекомендуется явно инициализировать код объекта с учетом нужного префикса до момента вызова метода записи.
Рассмотрим пример правильной установки номера с префиксом:
НовыйЭлемент = Справочники.Контрагенты.СоздатьЭлемент();
НовыйЭлемент.Наименование = "Новый партнер";
// Явно устанавливаем код с учетом префикса информационной базы или узла
НовыйЭлемент.УстановитьНовыйКод("УТ");
Попытка
НовыйЭлемент.Записать();
Исключение
// В случае возникновения коллизии обновляем кэш и повторяем генерацию
ОбновитьНумерациюОбъектов(Метаданные.Справочники.Контрагенты);
НовыйЭлемент.УстановитьНовыйКод("УТ");
НовыйЭлемент.Записать();
КонецПопытки;
Если для интеграции используется COM-соединение (comcntr), следует учитывать его зависимость от разрядности библиотек и операционной системы. Для повышения стабильности обменов рекомендуется переходить на современные интеграционные механизмы платформы: HTTP-сервисы, Web-сервисы (SOAP) или стандартный интерфейс OData, работающие по протоколу HTTP/HTTPS через веб-сервер.