Məzmuna keç
Tez Base

Регламентное задание 1С обрабатывает не все записи и не выдаёт ошибок: проверка и исправление цикла

· Dərc edilib:

Интеграции и обмены

Симптом выглядит так. Регламентное задание каждую ночь берёт записи с признаком “не обработано”, что-то с ними делает и снимает признак. Отрабатывает без ошибок, в журнале регистрации чисто, в логе стоит “обработано 5 000”. Утром в наборе опять висят тысячи записей, и новых среди них почти нет.

Если задание берёт записи порциями и сдвигает смещение на размер порции, почти наверняка дело в самом цикле. Ниже по порядку: как подтвердить это на своей базе, откуда берётся потеря, как переписать обход и что при этом сломается, если не подумать заранее.

Узнайте себя: признаки дефекта

Проверьте свой код по четырём вопросам. Если на все ответ “да”, вероятность высокая.

ВопросГде смотреть
Набор задаётся отбором по признаку, который обработка меняет?условие запроса или параметры вызова сервиса
Порции берутся со сдвигом: вторая страница, третья, смещение 100, 200?счётчик в цикле
Набор пересобирается на каждой порции, а не выбирается один раз на старте?где стоит вызов запроса или сервиса: внутри цикла или до него
Выход из цикла по пустой порции?условие Прервать

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

Холостой прогон: проверка за минуту вместо ночи

Ждать следующей ночи не нужно. Запустите обход своим же кодом, но вместо полной обработки только снимайте признак и собирайте ключи. Снимать признак обязательно: без этого набор не сжимается, прогон пройдёт по всем записям, и дефект не проявится. Поэтому запускайте на копии базы или на тестовом наборе.

// Холостой прогон на копии базы: считаем набор до, обходим, считаем после
Процедура ПроверитьОбход() Экспорт

	До = КоличествоНеобработанных();

	Собрано = Новый Соответствие;
	Смещение = 0;
	Размер = 100;

	Пока Истина Цикл
		Порция = ПолучитьНеобработанные(Смещение, Размер);
		Если Порция.Количество() = 0 Тогда
			Прервать;
		КонецЕсли;
		Для Каждого Запись Из Порция Цикл
			Собрано.Вставить(Запись.Ссылка, Истина);
			СнятьПризнак(Запись);   // то же действие, что делает задание
		КонецЦикла;
		Смещение = Смещение + Размер;
	КонецЦикла;

	После = КоличествоНеобработанных();

	Сообщить("До: " + До + ", обработано: " + Собрано.Количество()
		+ ", осталось: " + После);

КонецПроцедуры

Как читать результат:

  • осталось ноль: обход честный, ищите причину в другом месте;
  • обработано плюс осталось равно “до”, а осталось около половины: это он, сжимающийся набор под сдвигающимся смещением;
  • обработано плюс осталось больше “до”: набор рос во время прогона, смотрите раздел про дубли ниже.

Если ошибка в цикле, сверка обработанного с отправленным сойдётся идеально. Она проверяет, что каждая взятая запись обработана, а взяли не все. Ловит дефект только остаток.

Откуда берётся потеря

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

Пошагово на двадцати записях и порции в пять:

ШагВ наборе до шагаСмещениеВзялиПерешагнули
11-2001-5-
26-20511-156-10
36-10, 16-2010ничего6-10, 16-20

На третьем шаге в наборе десять записей, смещение тоже десять, порция пустая, и цикл честно выходит. Выход по пустой порции здесь означает “смещение догнало конец набора”, а вовсе не “набор кончился”. Обработано десять из двадцати.

Сколько теряется при разных размерах

Доля считается моделью ниже, её можно прогнать самому.

Записей в набореПорцияОбработано
10 00010050,0 %
1 0001050,0 %
1 00010050,0 %
1 00015055,0 %
1 00020060,0 %
1 00033366,6 %

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

Модель на встроенном языке, подставьте свои размеры:

Функция ОбработаноЗаПрогон(Всего, Страница)

	Набор = Новый Массив;
	Для Н = 1 По Всего Цикл
		Набор.Добавить(Н);
	КонецЦикла;

	Смещение = 0;
	Пока Смещение < Набор.Количество() Цикл
		Конец = Мин(Смещение + Страница, Набор.Количество());
		Если Конец <= Смещение Тогда
			Прервать;
		КонецЕсли;
		// обработанные уходят из набора; удаляем с конца, чтобы индексы не съехали
		Инд = Конец - 1;
		Пока Инд >= Смещение Цикл
			Набор.Удалить(Инд);
			Инд = Инд - 1;
		КонецЦикла;
		Смещение = Смещение + Страница;
	КонецЦикла;

	Возврат Всего - Набор.Количество();

КонецФункции

Для набора 20 и порции 4 функция вернёт 12, то есть шестьдесят процентов: пример того, что половина это нижняя граница, а не константа.

Как переписать цикл

Есть три варианта, и выбирать надо по тому, можете ли вы менять код.

ВариантКогда подходитЦена
Увеличить порциюникогда как исправлениемаскирует дефект до следующего роста набора
Повторять прогон, пока остаток не станет нулёмкод чужой, править нельзялишние прогоны: примерно 4 для 1 000 записей при порции 100 и 7 для 10 000
Всегда брать порцию с начала наборакод вашнужна защита от записей, которые не обрабатываются

Правильный вариант третий: смещения нет вообще.

Размер = 100;

Пока Истина Цикл

	// обработанные уже выпали из отбора, поэтому начало набора всегда свежее
	Порция = ПолучитьНеобработанные(0, Размер);

	Если Порция.Количество() = 0 Тогда
		Прервать;
	КонецЕсли;

	Для Каждого Запись Из Порция Цикл
		Обработать(Запись);
	КонецЦикла;

КонецЦикла;

Пустая порция теперь значит ровно то, что написано: в наборе ничего не осталось.

Что сломается, если на этом остановиться. Запись, которая не смогла обработаться (сервис ответил отказом, данные битые), признак не теряет и приходит в следующей порции снова. Цикл становится вечным, и одна плохая запись держит задание до таймаута. Нужен учёт попыток: регистр сведений с ключом записи и числом попыток, отбор “попыток меньше трёх” в том же запросе и отдельный отчёт по тем, кто уткнулся в лимит. Страховка попроще: предел итераций цикла с записью в журнал, если он сработал.

В старом варианте со смещением эта беда была не видна как раз потому, что плохая запись оставалась позади вместе с половиной хороших.

Сортировка в порции обязательна

Порция в запросе обычно выглядит так:

Запрос.Текст =
	"ВЫБРАТЬ ПЕРВЫЕ 100
	|	Ном.Ссылка КАК Ссылка
	|ИЗ
	|	Справочник.Номенклатура КАК Ном
	|ГДЕ
	|	НЕ Ном.ДанныеПолучены
	|
	|УПОРЯДОЧИТЬ ПО
	|	Ссылка";

Без УПОРЯДОЧИТЬ ПО запрос законен, но порядок строк тогда выбирает СУБД, и между вызовами он может отличаться. Мы видели такое на 8.3.27 с MS SQL, причину на своей связке не разбирали. Для обхода со смещением это означает, что пропуск становится случайным: сегодня пропущена одна запись, завтра другая, и дефект перестаёт воспроизводиться. Сортируйте по полю, которое не меняется при обработке. Ссылка годится, дата изменения и статус нет.

Обратный случай: набор растёт, и уходят дубли

Бывает зеркально: пока задание идёт по очереди, в неё поступают новые записи. Смещение тогда отстаёт от содержимого, следующая страница частично повторяет предыдущую, и часть записей отправляется дважды. Ошибок нет и здесь, получатель может принять оба раза.

Этот вариант замечают раньше, потому что дубль виден на той стороне и возвращается претензией. Лечение то же: убрать смещение и брать с начала. Плюс ключ идемпотентности в отправке, по которому получатель узнаёт повтор. Как повтор запроса к внешнему сервису превращается в дубль и какие операции можно повторять без опаски, разобрано в статье про таймаут обмена 1С с внешним сервисом.

Правило для обоих случаев одно: смещение работает только на наборе, который не меняется между страницами.

Что добавить в лог задания

Одна строка решает проблему на будущее. Рядом с “обработано” пишите “осталось по отбору после прогона”. У задания, которое должно опустошать набор, второе число хотя бы иногда обязано быть нулём. Если за неделю оно ни разу не обнулилось при небольшом притоке, у вас либо этот дефект, либо задание не успевает за потоком, и оба ответа стоит знать.

Если задание не стартует вовсе, это другая история: порядок проверки собран в статье про регламентное задание, которое не выполняется. А если ночная загрузка отработала, но привезла ноль строк, смотрите разбор загрузки, упавшей молча.

Чем искать такие циклы в своей базе

Если цикл сидит в обмене, который писали не вы, и править его страшно, это работа для доработки обменов 1С: найдём обход, перепишем с учётом попыток и добавим остаток в лог.

Bunu sizin əvəzinizə həll edə bilərəm

1C-i hər şeylə əlaqələndiririk: digər 1C bazaları, saytlar, CRM, banklar, dövlət sistemləri. "Qopan" və növbə yığan mübadilələri təmir edirik.

Qiyməti
450 000 ₸-dənmübadilə altsisteminin tam tətbiqi; vergilərsiz, nöqtəvi tapşırıqlar - daha ucuz

Yazmaq tezdir? Özünüz ölçün

Двадцать чужих обработок в справочнике дополнительных

Emalı aç

INFOSTART TECH EVENT 2026: конференция для 1с-специалистов. если собираетесь, регистрируйтесь по нашей ссылке. Регистрация →

Bunu da oxuyun

Проверка параметров HTTP-сервиса 1С: белый список, ошибка 400 и явные умолчания

Платформа не отвергает параметры, которых обработчик не ждёт, и опечатка в имени превращается в другой запрос с кодом 200. Разбираем четыре правила строгого входа для HTTP-сервиса на встроенном языке: белый список имён, 400 с понятным текстом, видимое умолчание и возраст данных в ответе. Код на BSL и проверка за минуту.

Расхождение остатков 1С и WMS: как устроить сверку, которой можно верить

Когда сверка 1С и WMS регулярно находит расхождения, а склад их не подтверждает, первым делом проверяют саму сверку. Шесть требований к ней таблицей, порядок проверки по шагам и цифры из разбора робота, который за 60 дней сам создал 62,7% оборота технического склада.

Регистрация изменений в плане обмена 1С: почему правка не встала в очередь

Между записью объекта и строкой в таблице изменений узла в БСП стоят пять ступеней: подписка на событие, включённая синхронизация, выборочная регистрация, авторегистрация и правила регистрации. Разбираем каждую по коду типовой УТ 11.5.22, запрос к очереди узла, замер на стенде и границу того, что показывает файл правил.