Автоматизация восстановления последовательности. Часть 4: собственно сама процедура

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

Было принято разделить рабочее время и нерабочее, чтобы можно было динамически менять время старта и остановки робота (на случай если бухгалтерия решит поработать после окончания рабочего дня). Соответственно константы Начало и Конец рабочего дня как раз и позволяют определить этот интервал. Тайм-аут – предназначен для определения паузы между попытками восстановления последовательности. Данные константы делались для старой версии обработки – в предложенном ниже варианте, они фактически не используются – так как в рабочее время восстановление последовательности останавливается, а в нерабочее время минимальная пауза 1 секунда не мешает производственным процессам.

Ключевая константа – блокировка робота – она позволяет фактически мгновенно остановить работу робота восстанавливающего последовательность через интерфейс 1С.

Ну и теперь, наконец-то, к коду обработки ))), правда после нескольких основных принципов работы:

  1. Размер периода, за который мы восстанавливаем последовательность динамический (от 1 до 600 секунд) и зависит от количества ошибок блокировки, которые произошли подряд.
  2. В случае ошибки блокировки, обработка берет динамическую паузу (от 3 до 10 минут), так в зависимости от числа ошибок подряд.
  3. Естественно каждый шаг процедуры логируется – я должен знать что делала система в любой момент времени.
// Все естественно в попытке – это без комментариев.
Попытка
  // Объявление переменных среды 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------------------------------------------------
КонецПопытки;
 
ЗавершитьработуСистемы(ложь);

Вот собственно и вся обработка. В следующих трех постах планирую:

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *