Наконец мы подошли к самому интересному (ради чего собственно все и затевалось) – к разработке самой процедуры восстановления последовательности. Вначале будет пара слов о настройках, которые были сделаны в системе 1С для управления процессом восстановления, а дальше пойдет большой блок кода с обильными комментариями. Текста минимум ))).
Итак, в системе были созданы и выведены на форму следующие константы:

Было принято разделить рабочее время и нерабочее, чтобы можно было динамически менять время старта и остановки робота (на случай если бухгалтерия решит поработать после окончания рабочего дня). Соответственно константы Начало и Конец рабочего дня как раз и позволяют определить этот интервал. Тайм-аут – предназначен для определения паузы между попытками восстановления последовательности. Данные константы делались для старой версии обработки – в предложенном ниже варианте, они фактически не используются – так как в рабочее время восстановление последовательности останавливается, а в нерабочее время минимальная пауза 1 секунда не мешает производственным процессам.
Ключевая константа – блокировка робота – она позволяет фактически мгновенно остановить работу робота восстанавливающего последовательность через интерфейс 1С.
Ну и теперь, наконец-то, к коду обработки ))), правда после нескольких основных принципов работы:
- Размер периода, за который мы восстанавливаем последовательность динамический (от 1 до 600 секунд) и зависит от количества ошибок блокировки, которые произошли подряд.
- В случае ошибки блокировки, обработка берет динамическую паузу (от 3 до 10 минут), так в зависимости от числа ошибок подряд.
- Естественно каждый шаг процедуры логируется – я должен знать что делала система в любой момент времени.
// Все естественно в попытке – это без комментариев.
Попытка
// Объявление переменных среды 1C
//------------------------------------------------------
ТекущийЧас=ТекущаяДата();
ТабПоследовательностей = Новый ТаблицаЗначений;
ТабПоследовательностей.Колонки.Добавить("ИмяПоследовательности");
ТабПоследовательностей.Колонки.Добавить("НаборКомбинаций");
ПустаяТаблица = Новый ТаблицаЗначений;
Стр = ТабПоследовательностей.Добавить();
Стр.ИмяПоследовательности = "ПартионныйУчет";
Стр.НаборКомбинаций = ПустаяТаблица;
Стр = ТабПоследовательностей.Добавить();
Стр.ИмяПоследовательности = "ПартионныйУчетБУ";
Стр.НаборКомбинаций = ПустаяТаблица;
Стр = ТабПоследовательностей.Добавить();
Стр.ИмяПоследовательности = "РасчетыПоПриобретениюОрганизации";
Стр.НаборКомбинаций = ПустаяТаблица;
Стр = ТабПоследовательностей.Добавить();
Стр.ИмяПоследовательности = "РасчетыПоРеализацииОрганизации";
Стр.НаборКомбинаций = ПустаяТаблица;
// Объявление переменных для работы алгоритма
//------------------------------------------------------
// Продолжать выполнять проведение
Продолжение = Истина;
// Произошла ошибка при восстановлении последовательности
WasError = Ложь;
// Количество ошибок возникших подряд
NumberOfErrors = 0;
// Начальное значение периода восстановления для рабочего времени (сек)
ActivityForWorkingDaySeconds = 10;
// Максимальное значение периода восстановления для рабочего времени (сек)
MaxActivityForWorkingDaySeconds = 10;
// Начальное значение периода восстановления для не рабочего времени (сек)
ActivityForResrSeconds = 60;
// Максимальное значение периода восстановления для не рабочего времени (сек)
MaxActivityForRestSeconds = 600;
// Объявление внутренних переменных цикла
//------------------------------------------------------
// Максимальное значение периода восстановления
MaxWorkSeconds = MaxActivityForWorkingDaySeconds;
// Текущее значение периода восстановления
WorkSeconds = ActivityForWorkingDaySeconds;
//--LOG_BEGIN-------------------------------------------------
// Логируем событие старта восстановления последовательности
Логирование.ЗаписатьОшибку(
глЗначениеПеременной("глТекущийПользователь"),
1, // Тип = Восстановление последовательности
"Информационное сообщение", // Краткое сообщение об ошибке
"Внешняя обработка/restore_robot.epf",
"Начато восстановление последовательности",
"",
FALSE
);
//--LOG_END------------------------------------------------
Пока Продолжение Цикл
Попытка
// Устанавливаем Дату восстановления
//------------------------------------------------------
Граница1 = Последовательности.ПартионныйУчет.ПолучитьГраницу().Дата;
Граница2 = Последовательности.ПартионныйУчетБУ.ПолучитьГраницу().Дата;
Граница3 = Последовательности.РасчетыПоПриобретениюОрганизации.ПолучитьГраницу().Дата;
Граница4 = Последовательности.РасчетыПоРеализацииОрганизации.ПолучитьГраницу().Дата;
ДатаВосстановления = Мин(Граница1, Граница2, Граница3, Граница4);
ТекущийЧас = Формат(ТекущаяДата(),"ДФ=Ч");
// Определяем период восстановления в зависимости от рабочих/нерабочих часов и количества ошибок
// Суббота и воскресенье считаются нерабочими днями в полном объеме
Если (ДеньНедели(ТекущаяДата()) = 7 ИЛИ ДеньНедели(ТекущаяДата()) = 6)
ИЛИ (Число(ТекущийЧас) < Константы.ГраницаНаУтро.Получить() или
Число(ТекущийЧас) >= константы.ГраницаНаВечер.Получить()) Тогда
MaxWorkSeconds = MaxActivityForRestSeconds;
Иначе
MaxWorkSeconds = MaxActivityForWorkingDaySeconds; // пауза для рабочего времени
Продолжение = ЛОЖЬ; // В РАБОЧЕЕ ВРЕМЯ ПОКА НЕ ПРОВОДИМ
КонецЕсли;
// В зависимости от ошибок в последней попытке
// увеличиваем или уменьшаем период восстановления,
// но не более максимального периода и не менее одной секунды
Если NumberOfErrors = 0 Тогда
WorkSeconds = WorkSeconds * 2;
Если WorkSeconds > MaxWorkSeconds Тогда
WorkSeconds = MaxWorkSeconds;
КонецЕсли;
Иначе
WorkSeconds = Цел(WorkSeconds / 2);
Если WorkSeconds < 1 Тогда
WorkSeconds = 1;
КонецЕсли;
КонецЕсли;
// Определяем даты восстановления и сбрасываем флаг ошибок
ДатаВосстановления = ДатаВосстановления + WorkSeconds;
WasError = Ложь;
// Проверки, а стоит ли продолжать восстанавливать или есть команда STOP
//------------------------------------------------------
// Если ушли за текущую дату, то останавливаем работу обработки
Если ДатаВосстановления > ТекущаяДата() Тогда
Продолжение = Ложь;
КонецЕсли;
// Выставлен флаг Блокировки восстановления последовательности
Если Константы.БлокировкаРобота.Получить() = Истина тогда
Продолжение = Ложь; //---действительно просят
КонецЕсли;
// УРА - все прошли - ВОССТАНАЛИВАЕМ!!!!
//------------------------------------------------------
Если Продолжение Тогда
//--LOG_BEGIN-------------------------------------------------
// Логируем работу восстановления последовательности
ДатаВформатеXML = "<Parameters><DocParameters
| SequenceDate='" + Формат(ДатаВосстановления, "ДФ='yyyy-MM-dd HH:mm:ss'") + "'
| WorkSeconds ='" + WorkSeconds + "'
| NumberOfErrors = '" + NumberOfErrors + "'
| MaxWorkSeconds = '" + MaxWorkSeconds + "'
|/></Parameters>";
Логирование.ЗаписатьОшибку(
глЗначениеПеременной("глТекущийПользователь"),
1, // Тип = Восстановление последовательности
"Информационное сообщение",
"Внешняя обработка/restore_robot.epf",
"Идет восстановление последовательности",
ДатаВформатеXML,
FALSE
);
//--LOG_END------------------------------------------------
// ---------------------------------------------------------
// Восстанавливаем последовательность
Попытка
// !!!!!!!!!!!!!!!!!!
// Нужна только эта строчка - остальное все обертка
// она одна работает, а все остальные нахлебники ;-)
Последовательности.Восстановить(ДатаВосстановления, ТабПоследовательностей);
// !!!!!!!!!!!!!!!!!!
// Если до этого были ошибки, то уменьшаем значение на единицу,
// но не менее нуля
Если NumberOfErrors > 0 Тогда
NumberOfErrors = NumberOfErrors - 1;
КонецЕсли;
Исключение
// Увеличивааем счетчик ошибок, но не более 10.
// Больше бес толку. 10 - это много ))))
WasError = Истина;
Если NumberOfErrors < 10 Тогда
NumberOfErrors = NumberOfErrors + 1;
КонецЕсли;
//--LOG_BEGIN-------------------------------------------------
// Записываем ошибки в регистр, для анализа
ДатаВформатеXML = "<Parameters><DocParameters
| WorkSeconds ='" + WorkSeconds + "'
| NumberOfErrors = '" + NumberOfErrors + "'
| MaxWorkSeconds = '" + MaxWorkSeconds + "'
|/></Parameters>";
Логирование.ЗаписатьОшибку(
глЗначениеПеременной("глТекущийПользователь"),
1, // Тип = Восстановление последовательности
"Ошибка восстановления последовательности",
"Внешняя обработка/restore_robot.epf",
ОписаниеОшибки(),
ДатаВформатеXML,
FALSE
);
//--LOG_END------------------------------------------------
КонецПопытки;
// -------------------------------------------------------------------
// Определяем паузу между операциями восстановления последовательности
// -------------------------------------------------------------------
Если WasError Тогда // Если была ошибка - то ставится большая пауза (размер зависит от числа ошибок подряд)
Если NumberOfErrors >= 10 Тогда
сек = 600;
ИначеЕсли NumberOfErrors >= 5 Тогда
сек = 300;
Иначе
сек = 180;
КонецЕсли;
Иначе
ТекущийЧас = Формат(ТекущаяДата(),"ДФ=Ч");
// Определяем паузу в зависимости от рабочих/нерабочих часов
// Суббота и воскресенье считаются нерабочими днями
Если (ДеньНедели(ТекущаяДата()) = 7 ИЛИ ДеньНедели(ТекущаяДата()) = 6)
ИЛИ (Число(ТекущийЧас) < Константы.ГраницаНаУтро.Получить() или
Число(ТекущийЧас) >= константы.ГраницаНаВечер.Получить()) Тогда
сек = константы.ТаймАутВНеРабочееВремя.Получить();
Иначе
сек = константы.ТаймАутВРабочееВремя.Получить(); // пауза для рабочего времени
Продолжение = ЛОЖЬ; // В РАБОЧЕЕ ВРЕМЯ ПОКА НЕ ПРОВОДИМ
КонецЕсли;
КонецЕсли;
// Определяем время до которого обработка держит паузу.
КонДата = ТекущаяДата() + сек;
Пока ТекущаяДата() < КонДата Цикл
// ждемссс....
КонецЦикла;
КонецЕсли;
Исключение
// Глобальная ошибка
WasError = Истина;
//--LOG_BEGIN-------------------------------------------------
// Записываем ошибки в регистр, для анализа
Логирование.ЗаписатьОшибку(
глЗначениеПеременной("глТекущийПользователь"),
1, // Тип = Восстановление последовательности
"Ошибка восстановления последовательности (CRITICAL)",
"Внешняя обработка/restore_robot.epf",
ОписаниеОшибки(),
"",
FALSE
);
//--LOG_END------------------------------------------------
КонецПопытки;
КонецЦикла;
//--LOG_BEGIN-------------------------------------------------
// Пишем о завершении работы
Логирование.ЗаписатьОшибку(
глЗначениеПеременной("глТекущийПользователь"),
1, // Тип = Восстановление последовательности
"Информационное сообщение",
"Внешняя обработка/restore_robot.epf",
"Завершено восстановление последовательности",
"",
FALSE
);
//--LOG_END------------------------------------------------
Исключение
// МЕГА-Глобальная ошибка
//--LOG_BEGIN-------------------------------------------------
// Записываем ошибки в регистр, для анализа
Логирование.ЗаписатьОшибку(
глЗначениеПеременной("глТекущийПользователь"),
1, // Тип = Восстановление последовательности
"Ошибка восстановления последовательности (CRITICAL)",
"Внешняя обработка/restore_robot.epf",
ОписаниеОшибки(),
"",
FALSE
);
//--LOG_END------------------------------------------------
КонецПопытки;
ЗавершитьработуСистемы(ложь);
Вот собственно и вся обработка. В следующих трех постах планирую:
- Описать работу утилиты, которая запускает приведенную выше обработку.
- Отчет, которые формируется для бизнеса по динамике восстановления последовательности.
- Отчет о том, насколько удалось достигнуть целей, поставленных в самом первом посте из данной серии и сравнение работы прежней версии обработки и нового варианта.