1С – пастырь

У клиента возникла задача. По соображениям безопасности нужно было проверять, запущена ли постоянно 1с у сотрудников в различных территориально удаленных подразделениях.

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

Уточнение задачи

При отсутствии отклика от 1С компьютера в течение 20 минут должно формироваться почтовое извещение.

Повторно такое извещение должно отправляться только через час.

Извещения должны приходить только в рабочее время работы сотрудников, для каждого компьютера оно разное.

В начале дня не должно быть ложных тревог, должен быть некоторый задел.

Если компьютер начал работу после извещения, об этом должно тоже приходить извещение.

Реализация

Для семафоров работы 1с у сотрудников я выделил в локальной сети общедоступный каталог. Флажки сделал в виде файлов, имя которых состояло из названия компьютеров:

 

Учитывая, что нужно хранить информацию о последнем извещении, решено было ее хранить в каталоге базы в отдельном файле check-settings.txt, чтобы не напрягать базу лишними операциями чтения и записи.

 

На компьютерах сотрудников периодически, раз в 3 минуты, выполнялся код вида:

ИмяФайла = "\\192.168.5.210\1c_obmen\here\" + СокрЛП(ИмяКомпьютера()) + ".xml";

Ф = Новый ТекстовыйДокумент();

Ф.Записать(ИмяФайла);

 

В центре периодически выполнялся код вида:

//Пути, настройки

ИмяКаталогаПроверок = "c:\1c_obmen\here\";

ФайлСохраненияНастроек = ФРАНЧ.ПолучитьКаталогБазы() + "\check-settings.txt";

КоличествоМинутДляИзвещения = 20;

КоличествоМинутДляПовторногоИзвещения = 60;

КоличествоМинутЗащитыОтСтартаКомпа = 45; //45 минут с момента старта компа ждем, не работаем

ИсхПолучатели = "boss@office.ru, support@office.ru, security@office.ru";

 

//Восстанавливаем из файла список последних оповещений

Попытка

       Т = Новый ТекстовыйДокумент();

       Т.Прочитать(ФайлСохраненияНастроек);

       СтруктураНастроек = ЗначениеИзСтрокиВнутр(Т.ПолучитьТекст());

Исключение

       СтруктураНастроек = Новый Структура("Компы", Новый ТаблицаЗначений());

       СтруктураНастроек.Компы.Колонки.Добавить("Комп");

       СтруктураНастроек.Компы.Колонки.Добавить("ДатаПоследнегоИзвещения");

       СтруктураНастроек.Вставить("ДатаПоследнейПроверки", '00010101');

КонецПопытки;

 

//Получаем список компов, от которых есть отзывы на сервере

ТекЗадача = Справочники._ЗадачиПоРасписанию.НайтиПоКоду("ПЭПР1СРАБ");

З = Новый Запрос(

"ВЫБРАТЬ

|      _ЗадачиПоРасписаниюМеста.Комп.Ссылка КАК Ссылка,

|      _ЗадачиПоРасписаниюМеста.Комп.Код КАК Код

|ИЗ

|      Справочник._ЗадачиПоРасписанию.Места КАК _ЗадачиПоРасписаниюМеста ГДЕ Ссылка = &ТекЗадача");

З.УстановитьПараметр("ТекЗадача", ТекЗадача);

Сообщить(ТекЗадача);

ТЗ = З.Выполнить().Выгрузить();

 

//Перебираем компы

Для Каждого Строка ИЗ ТЗ Цикл

       ТекКомп = Строка.Ссылка;

       //Проверяем, что текущее время подпадает под график работы сотрудника на компе

       СтруктураДанныхКомпа = _УчетРабочегоВремени.ПолучитьДанныеПоУчетуРабочегоВремениНаДату(ТекущаяДата(), ТекКомп);

       ВремяНачалаРаботыКомпа = СтруктураДанныхКомп.ВремяНачалаРаботы;

       ВремяОкончанияРаботыКомпа = СтруктураДанныхКомпа.ВремяОкончанияРаботы;

       Если НЕ ЗначениеЗаполнено(ВремяНачалаРаботыКомпа) ИЛИ НЕ ЗначениеЗаполнено(ВремяОкончанияРаботыКомпа) Тогда

             Продолжить;

       КонецЕсли;

      

       Сейчас = ТекущаяДата();

       ВремяСейчас = Дата(1, 1, 1, Час(Сейчас), Минута(Сейчас), Секунда(Сейчас));

      

       //Если комп еще не работает, не извещать (оставляем небольшой задел при старте компа)...

       Если ВремяСейчас < (ВремяНачалаРаботыКомпа + КоличествоМинутЗащитыОтСтартаКомпа * 60) ИЛИ ВремяСейчас > ВремяОкончанияРаботыКомпа Тогда

             Продолжить;

       КонецЕсли;

      

       //Проверяем извещения

       ТекКод = СокрЛП(Строка.Код);

       Ф = Новый Файл(ИмяКаталогаПроверок + "\" + ТекКод + ".xml");

       Если НЕ Ф.Существует() Тогда

             ДатаПроверки = '00010101';

       Иначе

             ДатаПроверки = Ф.ПолучитьВремяИзменения();

       КонецЕсли;

       //Сообщить("" + Строка.Ссылка + ": " + ДатаПроверки );

      

       Получатели = ИсхПолучатели;

       //Получатели = Получатели + "," + ТекКомп.ЭлектроннаяПочта;

       Получатели = Получатели + "," + ФРАНЧ.ПолучитьПочтовыеАдресаРуководителейСотрудников(ТекКомп);

       Получатели = ФРАНЧ.ДатьУникальныеПочтовыеАдреса(Получатели);

 

      

       ОтправлятьПисьмо = ложь;

      

      

       //Получаем строку с информацией о компе

       ИскСтрока = СтруктураНастроек.Компы.Найти(Строка.Ссылка, "Комп");

       ДатаПоследнегоИзвещения = '00010101';

       Если ИскСтрока = Неопределено Тогда

             ИскСтрока = СтруктураНастроек.Компы.Добавить();

             ИскСтрока.Комп = Строка.Ссылка;

             ИскСтрока.ДатаПоследнегоИзвещения = '00010101';

       КонецЕсли;

      

       //Получаем дату последнего извещения. Если это не сегодняшняя дата, сбрасываем ее...

       Если НачалоДня(ИскСтрока.ДатаПоследнегоИзвещения) <> НачалоДня(ТекущаяДата()) Тогда

             ИскСтрока.ДатаПоследнегоИзвещения = '00010101';

       КонецЕсли;

       ДатаПоследнегоИзвещения = ИскСтрока.ДатаПоследнегоИзвещения;

 

      

       //Если проверка не пройдена, т.е. комп не доложился...

       Если ТекущаяДата() - ДатаПроверки  > КоличествоМинутДляИзвещения * 60 Тогда

             //Нужно ли извещать

             //Если ранее не извещали или прошло нужное количество минут

             Извещать = НЕ ЗначениеЗаполнено(ДатаПоследнегоИзвещения) ИЛИ ТекущаяДата() - ДатаПоследнегоИзвещения > КоличествоМинутДляПовторногоИзвещения * 60;           

             Если Извещать Тогда

                    //Извещаем

                    ИскСтрока.ДатаПоследнегоИзвещения = ТекущаяДата();

                   

                    //Формируем письмо

                    Тема = "Не запущена база 1с на компе: " + Строка.Ссылка + " Нет подтверждения " + ?(НЕ ЗначениеЗаполнено(ДатаПроверки), "совсем", "" + Цел((ТекущаяДата() - ДатаПроверки) / 60) + " минут") + ".";

                    Тело = Тема;

                    Если ЗначениеЗаполнено(ДатаПоследнегоИзвещения) Тогда

                           Тело = Тело + Символы.ПС + "Дата последней активности компа: " + ?(НЕ ЗначениеЗаполнено(ДатаПроверки), " не указана", ДатаПроверки);

                           Тело = Тело + Символы.ПС + "Дата последнего извещения: " + ДатаПоследнегоИзвещения;

                    КонецЕсли;

                    //Нужно отправлять письмо

                    ОтправлятьПисьмо = истина;

             КонецЕсли;

            

       Иначе//Если проверка пройдена, т.е. комп доложился нормально

             //Если извещение было

             Если ЗначениеЗаполнено(ДатаПоследнегоИзвещения) Тогда

                    Если  ТекущаяДата() - ДатаПоследнегоИзвещения < КоличествоМинутДляПовторногоИзвещения * 60 Тогда

                           Тема = "База 1с опять заработала после не пройденной проверки на компе:  " + Строка.Ссылка + " Спустя " + Цел((ТекущаяДата() - ДатаПоследнегоИзвещения) / 60) + " минут после последнего извещения.";

                           Тело = Тема;

                           Если ЗначениеЗаполнено(ДатаПоследнегоИзвещения) Тогда

                                  Тело = Тело + Символы.ПС + "Дата последней активности компа: " + ?(НЕ ЗначениеЗаполнено(ДатаПроверки), " не указана", ДатаПроверки);

                                  Тело = Тело + Символы.ПС + "Дата последнего извещения: " + ДатаПоследнегоИзвещения;

                           КонецЕсли;

                           //Нужно отправлять письмо

                           ОтправлятьПисьмо = истина;

                           ИскСтрока.ДатаПоследнегоИзвещения = '00010101'; //Сбрасываем дату последнего извещения

                    КонецЕсли;

             КонецЕсли;

       КонецЕсли;

      

       //Отправляем письмо

       Если ОтправлятьПисьмо Тогда

             Сообщить(Тема);

             Сообщить(Тело);

             Тело = Тело + Символы.ПС + "Отправлено в: " + ТекущаяДата();

             ФРАНЧ.ОтправитьПисьмо(, Получатели, Тема, Тело);

       КонецЕсли;

      

КонецЦикла;

 

 

//Сохраняем в файл список последних оповещений

Т = Новый ТекстовыйДокумент();

Т.УстановитьТекст(ЗначениеВСтрокуВнутр(СтруктураНастроек));

Т.Вывод = ИспользованиеВывода.Разрешить;

Т.Записать(ФайлСохраненияНастроек);

Сообщить(ФайлСохраненияНастроек);

Недостатки решения и резюме

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

 

Таким образом достаточно просто была решена поставленная заказчиком задача.