Автоматическая очистка кэша конфигурации 1С 8.1, 8.2, 8.3 для сеанса текущего пользователя

Автоматическая очистка кэша конфигурации 1С для сеанса текущего пользователя (при динамическом обновлении или ручном интерактивном запуске)

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

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

Алгоритм:

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

2) В глобальном модуле обычного приложения (для управляемых форм модуль управляемого приложения) в процедуре ПриНачалеРаботыСистемы() прописываем обработчик ожидания "ПодключитьОбработчикОжидания("ПроверкаДинОбновления",60);"

Процедура ПроверкаДинОбновления() Экспорт
Если КонфигурацияБазыДанныхИзмененаДинамически() Тогда  //добавляем в очередь обновления кэша - когда будет выходить - очистится кэш конфигурации
Наб1 = РегистрыСведений.НеобходимостьОчисткиКэша.СоздатьНаборЗаписей();
Наб1.Отбор.Пользователь.Установить(ПользователиИнформационнойБазы.ТекущийПользователь().Имя);
наб1.Прочитать();
Если Наб1.Количество()<>0 Тогда
Возврат;
КонецЕсли;
зап1 = наб1.Добавить();
зап1.Пользователь = ПользователиИнформационнойБазы.ТекущийПользователь().Имя;
наб1.Записать();
КонецЕсли;
КонецПроцедуры

 

3)  При завершении работы в глобальном модуле прописываем вызов функции очистки кэша:

Процедура ПриЗавершенииРаботыСистемы()

ОчиститьКэш1С();

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

 

Собственно сама функция очистки кэша:

Процедура ОчиститьКэш1С()
//определяем нужно ли текущему пользователю очистка кэша
запр1 = Новый Запрос;
запр1.УстановитьПараметр("Пользователь", ПользователиИнформационнойБазы.ТекущийПользователь().Имя);
запр1.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1
|    НеобходимостьОчисткиКэша.Пользователь
|ИЗ
|    РегистрСведений.НеобходимостьОчисткиКэша КАК НеобходимостьОчисткиКэша
|ГДЕ
|    НеобходимостьОчисткиКэша.Пользователь = &Пользователь";
тз1 = запр1.Выполнить().Выгрузить();
Если тз1.Количество() = 0 Тогда
Возврат;
КонецЕсли;

СтрокаПоиска = "Connect="+СтрокаСоединенияИнформационнойБазы();
Ф1 = Новый ТекстовыйДокумент;
ф1.ТолькоПросмотр = Истина;
Шелл = Новый COMОбъект("WScript.Shell");
АППДата = Шелл.ExpandEnvironmentStrings("%APPDATA%");
АППДата2 = Шелл.ExpandEnvironmentStrings("%LOCALAPPDATA%");
ИмяФайла = АППДата+"1C1CEStartibases.v8i";
//сообщить(ИмяФайла);
ф1.Прочитать(ИмяФайла);
Для сч1 = 1 по ф1.КоличествоСтрок() Цикл
стр1 = СокрЛП(ф1.ПолучитьСтроку(сч1));
Если стр1 <> СтрокаПоиска Тогда
Продолжить;
КонецЕсли;
ИДБазы = стрЗаменить(СокрЛП(ф1.ПолучитьСтроку(сч1 + 1)), "ID=", "");
//сообщить(ИДБазы);
прервать;
КонецЦикла;
Путь1 = АППДата + "1C1Cv82"+ИДБазы+"";   //пользовательские настройки  - ничего не трогаем
Путь2 = АППДата2 + "1C1Cv82"+ИДБазы+"*";   //кэш конфигурации - удаляем только его

ИмяСкрипта1 = ПолучитьИмяВременногоФайла("cmd");

ф2 = Новый ТекстовыйДокумент;
//Удал1 = "del /f /s /q """+Путь1+""""; //пользовательские настройки
Удал2 = "del /f /s /q """+Путь2+""""; //кеш конфигурации
ф2.ДобавитьСтроку("ping -n 11 127.0.0.1 & "+Удал2);  //пауза 10 сек + удаление кеша конфигурации -  В нескольких строках не срабатывает!!!
ф2.Записать(ИмяСкрипта1, КодировкаТекста.ANSI);
Шелл.Run(""""+ИмяСкрипта1+"""",0);


//удаляем из очереди очистки кэша текущего пользователя
Наб1 = РегистрыСведений.НеобходимостьОчисткиКэша.СоздатьНаборЗаписей();
Наб1.Отбор.Пользователь.Установить(ПользователиИнформационнойБазы.ТекущийПользователь().Имя);
наб1.Прочитать();
наб1.Очистить();
наб1.Записать();
КонецПроцедуры

 

Можно также в интерфейс пользователя добавить следующую команду — очистить кэш конфигурации вручную (если есть непонятные глюки с программой):

Процедура Вызов_ОчиститьКэш1С() Экспорт //пользователь сам решает почистить кэш
ТекстВопроса = "Программа 1С будет завершена. Повторно зайти в 1С можно будет через 1 минуту. Продолжить?";
Ответ = Вопрос(ТекстВопроса, РежимДиалогаВопрос.ДаНет, , КодВозвратаДиалога.Да,);
Если Ответ <> КодВозвратаДиалога.Да Тогда
Возврат;
КонецЕсли;
Наб1 = РегистрыСведений.НеобходимостьОчисткиКэша.СоздатьНаборЗаписей();
Наб1.Отбор.Пользователь.Установить(ПользователиИнформационнойБазы.ТекущийПользователь().Имя);
наб1.Прочитать();
Если Наб1.Количество() = 0 Тогда
зап1 = наб1.Добавить();
зап1.Пользователь = ПользователиИнформационнойБазы.ТекущийПользователь().Имя;
наб1.Записать();
КонецЕсли;
ЗавершитьРаботуСистемы(Ложь, Ложь);
КонецПроцедуры

 

Примечание: процедура очистки корректно отрабатывает при локальном подключении и терминальном подключении. При подключении на ферму с несколькими терминальными серверами — процедура работает некорректно, из-за того что очищает кэш только для текущего терминального сервера, не затрагивая остальные сервера фермы.

18 Comments

  1. DrAku1a

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

    Reply
  2. user764938

    Подскажите пожалуйста, «Процедура ОчиститьКэш1С» использует запрос, у меня конфигуратор ругается на Элемент «Запрос», я не очень понимаю, разве запрос вообще можно сделать в модуле управляемых приложений»? Возможно я делаю что-то не то?

    Reply
  3. golovkodv

    В управляемых формах чтение данных с регистра «НеобходимостьОчисткиКэша» необходимо прописывать в серверной функции, а саму очистку в клиентской, т.е. разделить процедуру ОчиститьКэш1С на 2 части — серверную и клиентскую.

    Reply
  4. w-divin

    Очень смутил момент:

    ИмяФайла = АППДата+»1C1CEStartibases.v8i»;

    //сообщить(ИмяФайла);

    ф1.Прочитать(ИмяФайла);

    у меня везде этот файлик пуст — опубликованы приложения с прописанной строкой подключения….

    Reply
  5. user764938

    (3) Спасибо!

    Reply
  6. frkbvfnjh

    А разве кэш 1С можно удалить из самого 1С пока он работает?

    Какие-то файлы все равно будут заняты же

    Reply
  7. golovkodv

    (6)

    У меня на закрытие приложения 1с дается 10 сек («ping -n 11 127.0.0.1»).

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

    Reply
  8. golovkodv

    (4)

    Не могу даже сказать.

    У меня файл «ibases.v8i» всегда присутствует.

    Может при веб-подключении его нет.

    Как тогда найти ID базы не знаю

    Reply
  9. japopov

    Вопрос, что будет на линуксовых и веб-клиентах, излишен, да? Очень костыльное и ограниченное решение.

    Reply
  10. golovkodv

    Кому-то может и пригодится

    Reply
  11. zxc753

    А еще можно использовать Обновлятор 1С)

    Reply
  12. madonov

    Зачем проверять динамическое обновление каждую минуту?

    Зачем писать в регистр и читать из него?

    Почему нельзя выполнить эту проверку 1 раз при завершении работы системы?

    Не очень понимаю зачем столько шагов. Почему не сделать так?

    Процедура ПриЗавершенииРаботыСистемы()
    ОчиститьКэш1С();
    КонецПроцедуры
    
    
    Процедура ОчиститьКэш1С()
    //определяем нужно ли текущему пользователю очистка кэша
    Если не КонфигурацияБазыДанныхИзмененаДинамически() Тогда
    Возврат;
    КонецЕсли;
    
    СтрокаПоиска = «Connect=»+СтрокаСоединенияИнформационнойБазы();
    Ф1 = Новый ТекстовыйДокумент;
    ф1.ТолькоПросмотр = Истина;
    Шелл = Новый COMОбъект(«WScript.Shell»);
    //АППДата = Шелл.ExpandEnvironmentStrings(«%APPDATA%»);
    АППДата2 = Шелл.ExpandEnvironmentStrings(«%LOCALAPPDATA%»);
    ИмяФайла = АППДата+»1C1CEStartibases.v8i»;
    //сообщить(ИмяФайла);
    ф1.Прочитать(ИмяФайла);
    Для сч1 = 1 по ф1.КоличествоСтрок() Цикл
    стр1 = СокрЛП(ф1.ПолучитьСтроку(сч1));
    Если стр1 <> СтрокаПоиска Тогда
    Продолжить;
    КонецЕсли;
    ИДБазы = стрЗаменить(СокрЛП(ф1.ПолучитьСтроку(сч1 + 1)), «ID=», «»);
    //сообщить(ИДБазы);
    прервать;
    КонецЦикла;
    //Путь1 = АППДата + «1C1Cv82″+ИДБазы+»»;   //пользовательские настройки  — ничего не трогаем
    Путь2 = АППДата2 + «1C1Cv82″+ИДБазы+»*»;   //кэш конфигурации — удаляем только его
    
    ИмяСкрипта1 = ПолучитьИмяВременногоФайла(«cmd»);
    
    ф2 = Новый ТекстовыйДокумент;
    //Удал1 = «del /f /s /q «»»+Путь1+»»»»; //пользовательские настройки
    Удал2 = «del /f /s /q «»»+Путь2+»»»»; //кеш конфигурации
    ф2.ДобавитьСтроку(«ping -n 11 127.0.0.1 & «+Удал2);  //пауза 10 сек + удаление кеша конфигурации —  В нескольких строках не срабатывает!!!
    ф2.Записать(ИмяСкрипта1, КодировкаТекста.ANSI);
    Шелл.Run(«»»»+ИмяСкрипта1+»»»»,0);
    
    КонецПроцедуры

    Показать

    Reply
  13. madonov

    Ну и вообще, надежность такого подхода несколько хромает:

    Пользователь открыл 1 экземпляр программы,

    Пользователь открыл 2 экземпляр программы на этом же ПК под этой же учетной записью,

    Динамическое обновление — пользователь в очереди на очистку кэша,

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

    Справедливости ради стоит отметить, что если проверять наличие динамического обновления при завершении, то такая коллизия тоже возможна, но при ином сценарии:

    Пользователь открыл 1 экземпляр программы,

    Динамическое обновление,

    Пользователь открыл 2 экземпляр программы на этом же ПК под этой же учетной записью,

    Пользователь закрыл 1 экземпляр программы — однако очистка не произошла, тк открыт 2 экземпляр программы.

    Пользователь закрыл 2 экземпляр программы — однако во время работы этого экземпляра динамического обновления не происходило и кэш не очищается.

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

    Reply
  14. golovkodv

    (12)

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

    Reply
  15. golovkodv

    (13)

    У меня на работе для пользователей не предусмотрено открытие нескольких экземпляров 1с. Поэтому я их и не рассматривал. Но думаю можно и такой случай предусмотреть: При завершении работы просмотреть активные сеансы (функция «ПолучитьСеансыИнформационнойБазы «) для своего текущего пользователя. И запускать очистку только если сеанс текущего пользователя присутствует в единственном числе . Иначе ничего не делать.

    Reply
  16. Andle

    Как отработает очистка, если у пользователя включена защита от опасных действий; база прописана в списке баз больше одного раза; настроен общий (на сетевом ресурсе) список баз?

    Reply
  17. golovkodv

    (16)

    1) там не запускаются никаких внешних обработок — поэтому все будет работать

    2) по коду видно — находит нужную первую запись ид базы и останавливает цикл поиска. Не понимаю смысла заводить 2 одинаковые строчки в списке баз. ИД базы определяет первую. С кэшем первой дальше и работает — ее и очищает. Последующие строки с таким ид не обрабатывает. Ходите обрабатывать — допилите код немного.

    3) этого не знаю. Не тестил такой вариант.

    Reply
  18. websamson

    (2) Для УФ есть параметр запуска /ClearCache

    Reply

Leave a Comment

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