Робот 24/7 - старт-стопный механизм...?

Автор Злоп, 12 апреля 2025, 18:55

« назад - далее »

Злоп

Вот, допустим, есть сеанс 77, робот 24/7
Нужны технологические окна, для проведения работ/обновления.
Допустим, кидаем файл-семафор - робот завершается (ну и прочие сеансы также)
Сделали что надо по техобслуживанию, файл-семафор убили.
Надо чтобы робот автоматом запустился.
Как это сделать? Ставим в планировщик виндовз задание (например, раз в 5 мин), которое делает типа так:
- проверяем наличие файл-семафор, если есть - ничего не делаем
- файл-семафора нет, удаляем в каталоге робота *.lck
- проверяем наличие в каталоге робота *.lck? если есть - ничего не делаем (робот уже работает), если нет - запускаем сеанс робота
.
типа так?
может еще какие варианты попроще/поизящнее есть?

Харлампий Дымба

А вот тот, кто семафор убивает в момент окончания тех.обслуживания, разве не может следом запустить робота?

Злоп

Может, конечно, но все равно придется делать отдельный ярлык-задание на запуск, чтобы не болтался рядом в том же вин-сеансе пользователя

Ветер в поле

У меня реализовано так. Изначально делалось для контроля за работой программы. Т.е. если робот завис или упал из-за ошибки. Каждую минуту (у меня сейчас 3 минуты) робот обновляет сигнальный файл, в котором сохранен ИД процесса робота в Windows. Также каждую минуту планировщик запускает написанную на C# программу, которая проверяет время изменения сигнального файла. Если файл не менялся более 5 минут (настраивается), то если есть процесс, который записан в сигнальном файле, то он сбрасывается. После этого запускается процесс робота.
Всё вроде бы просто, но на некоторых серверах этот процесс как-то калечно начинает работать - каждую минуту запускает процесс робота до тех пор пока Windows говорит - всё, ресурсы для запуска закончены...

У механизма есть еще один недостаток - чтобы он работал, необходимо чтобы под пользователем Windows был выполнен вход в сеанс. Т.е. после перезагрузки или сеанс срубили из Диспетчера служб удаленных рабочих столов.

В роботе должен быть такой код:
Перем глСтатус;
Перем СледующееОбновлениеФайлаФлагаРаботы;
Перем ПериодОбновленияФайлаФлагаРаботыСС;
Перем ИмяФайлаФлагаРаботы;
Перем ИДТекущегоПроцесса1С;

//*****************************************************************************
// Функция возвращает PID процесса 1с
// Подсказал "Кириллка" с форума "Миста"
Функция глПолучитьPID() Экспорт

  чPID = -1;
  Попытка
    oLocator = СоздатьОбъект("WbemScripting.SWbemLocator");
    oService = oLocator.ConnectServer(".", "root\CIMV2");
    
    // Запускаем дочерний rundll32.exe
    oShell = СоздатьОбъект("WScript.Shell");
    oApp = oShell.Exec("rundll32.exe kernel32,Sleep");
    // Получаем rundll32 по PID'у
    oChildProcess = oService.Get("Win32_Process.Handle=" + oApp.ProcessID);
    // Получаем PID родительского процесса - 1с
    чPID = oChildProcess.ParentProcessID;
    // Завершаем rundll32, чтобы не мусорить
    oChildProcess.Terminate();
  Исключение
    // нуу, может не быть прав на эти вещи, например.
    КонецПопытки;
    
  Возврат чPID;
    
КонецФункции //глПолучитьPID

//*****************************************************************************
Процедура ПриИзмененииФлагаРаботыПрограммы()
    
    Если флОбновлятьФлагРаботыПрограммы = 1 Тогда
        СледующееОбновлениеФайлаФлагаРаботы = глСтрТекДатаВремя();
        ПериодОбновленияФайлаФлагаРаботыСС = 180;
        ИмяФайлаФлагаРаботы = КаталогВременныхФайлов() + ИмяПользователя() + ".flg";
        ИДТекущегоПроцесса1С = Строка(глПолучитьPID());
    КонецЕсли;
    
КонецПроцедуры //ПриИзмененииФлагаРаботыПрограммы

//*****************************************************************************
Процедура РабочийПроцесс()
    
    Если глСтатус = 0 Тогда
        Возврат;
    КонецЕсли;
    
    ФормаРасш.ОбработкаОжидания("РабочийПроцесс", ИнтервалОтправкиСМС * 1000);
    глСервис.ВнешнееСобытие("Форма", "РабочийПроцесс", "");
    
    глСтатус = 1; //в ожидании
    
КонецПроцедуры //РабочийПроцесс

//*****************************************************************************
Процедура ЗапускСлужбы(ЗапуститьЧерез=100)
    
    глСтатус = 1;
    Форма.ттСтатус.Заголовок("Процесс запущен...");
    
    ФормаРасш = СоздатьОбъект("РасширениеФормы");
    ФормаРасш.ОбработкаОжидания("РабочийПроцесс", ЗапуститьЧерез);
    
КонецПроцедуры //ЗапускСлужбы

//*****************************************************************************
Процедура ОстановитьСлужбу()
    
    Если глСтатус > 0 Тогда
        глСтатус = 0;
        ФормаРасш.ОбработкаОжидания("РабочийПроцесс", 0);
        Форма.ттСтатус.Заголовок("Процесс остановлен...");
    КонецЕсли;
    
КонецПроцедуры //ОстановитьСлужбу

//*****************************************************************************
Процедура ОбработкаВнешнегоСобытия(Источник, Событие, Данные)

    Если (Источник <> "Форма") ИЛИ (Событие <> "РабочийПроцесс") Тогда
        глВывестиМногострочноеСообщение("Источник = " + Источник + " Событие = " + Событие + " Данные = " + Данные);
        Возврат;
    КонецЕсли;

    СохрСтатус = глСтатус;
    глСтатус = 0;

    Если флОбновлятьФлагРаботыПрограммы = 1 Тогда
        СтрДатаВремяТекущийМомент = глСтрТекДатаВремя();
        Если СледующееОбновлениеФайлаФлагаРаботы <= СтрДатаВремяТекущийМомент Тогда
            ТекстФайлаФлага = СоздатьОбъект("Текст");
            ТекстФайлаФлага.ДобавитьСтроку(ИДТекущегоПроцесса1С);
            ТекстФайлаФлага.Записать(ИмяФайлаФлагаРаботы);
            
            СледующееОбновлениеФайлаФлагаРаботы = глДобавитьКСтрДатаВремя(СтрДатаВремяТекущийМомент, 0, 0, 0, ПериодОбновленияФайлаФлагаРаботыСС);
        КонецЕсли;
    КонецЕсли;

    //Здесь выполняем нужные нам действия

    глСтатус = СохрСтатус;
    
КонецПроцедуры //ОбработкаВнешнегоСобытия

//*****************************************************************************
Процедура ПриОткрытии() //предопределенная
    
    глСтатус = 0;

    флОбновлятьФлагРаботыПрограммы = ВосстановитьЗначение("РегламентныеЗадачи_флОбновлятьФлагРаботыПрограммы");
    ПриИзмененииФлагаРаботыПрограммы();

    Если ТипЗначенияСтр(Форма.Параметр) = "СписокЗначений" Тогда
        Если Форма.Параметр.Получить("Команда") = "Запустить" Тогда
            оЗапускПоТаймеру = СоздатьОбъект("Общие.ЗапускПоТаймеру");
            оЗапускПоТаймеру.Инит(Контекст,
                "Процедура _ЗапускСлужбы()
                |    ЗапускСлужбы();
                |КонецПроцедуры",
                "_ЗапускСлужбы");
            оЗапускПоТаймеру.Запустить(1000);
        КонецЕсли;
    КонецЕсли;

КонецПроцедуры //ПриОткрытии

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

Настройки контролирующей программы находятся в set.ini
Там есть строка с disable=0. Она означает, что необходимо контролировать. Если выставить в параметр в 1, то программа не будет осуществлять контроль. Это удобно, когда нужно сделать сервисные действия (обновить конфу, например)
Архив с программой: https://disk.yandex.ru/d/8jXYXRN7WvEISQ

Злоп