Автоматическая очистка кэша конфигурации 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%");
    ИмяФайла = АППДата+"\1C\1CEStart\ibases.v8i";
    //сообщить(ИмяФайла);
    ф1.Прочитать(ИмяФайла);
    Для сч1 = 1 по ф1.КоличествоСтрок() Цикл
        стр1 = СокрЛП(ф1.ПолучитьСтроку(сч1));
        Если стр1 <> СтрокаПоиска Тогда
            Продолжить;
        КонецЕсли;
        ИДБазы = стрЗаменить(СокрЛП(ф1.ПолучитьСтроку(сч1 + 1)), "ID=", "");
        //сообщить(ИДБазы);
        прервать;
    КонецЦикла;
    Путь1 = АППДата + "\1C\1Cv82\"+ИДБазы+"\";   //пользовательские настройки  - ничего не трогаем
    Путь2 = АППДата2 + "\1C\1Cv82\"+ИДБазы+"\*";   //кэш конфигурации - удаляем только его
    
    ИмяСкрипта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.Записать();
    КонецЕсли;
    ЗавершитьРаботуСистемы(Ложь, Ложь);    
КонецПроцедуры

 

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

См. также

Комментарии
1. Андрей Акулов (DrAku1a) 1219 15.11.17 09:10 Сейчас в теме
В стандартных конфигурациях можно использовать механизмы настроек пользователя, чтобы не городить отдельный регистр.
Timon_132; +1 Ответить
2. Дмитрий Сусский (user764938) 15.11.17 09:51 Сейчас в теме
Подскажите пожалуйста, "Процедура ОчиститьКэш1С" использует запрос, у меня конфигуратор ругается на Элемент "Запрос", я не очень понимаю, разве запрос вообще можно сделать в модуле управляемых приложений"? Возможно я делаю что-то не то?
3. Дмитрий Головко (golovkodv) 54 15.11.17 10:38 Сейчас в теме
В управляемых формах чтение данных с регистра "НеобходимостьОчисткиКэша" необходимо прописывать в серверной функции, а саму очистку в клиентской, т.е. разделить процедуру ОчиститьКэш1С на 2 части - серверную и клиентскую.
sqncng; user764938; +2 Ответить
5. Дмитрий Сусский (user764938) 15.11.17 10:49 Сейчас в теме
4. Дмитрий Елисеев (w-divin) 15.11.17 10:46 Сейчас в теме
Очень смутил момент:
ИмяФайла = АППДата+"\1C\1CEStart\ibases.v8i";
//сообщить(ИмяФайла);
ф1.Прочитать(ИмяФайла);


у меня везде этот файлик пуст - опубликованы приложения с прописанной строкой подключения....
8. Дмитрий Головко (golovkodv) 54 15.11.17 13:03 Сейчас в теме
(4)
Не могу даже сказать.
У меня файл "ibases.v8i" всегда присутствует.
Может при веб-подключении его нет.
Как тогда найти ID базы не знаю
6. Андрей Лукин (frkbvfnjh) 250 15.11.17 11:32 Сейчас в теме
А разве кэш 1С можно удалить из самого 1С пока он работает?
Какие-то файлы все равно будут заняты же
juricher; +1 Ответить
7. Дмитрий Головко (golovkodv) 54 15.11.17 13:01 Сейчас в теме
(6)
У меня на закрытие приложения 1с дается 10 сек ("ping -n 11 127.0.0.1").
1с закрывается, а командная консоль еще висит и потом делает, что нужно.
9. J Popov (japopov) 37 15.11.17 15:00 Сейчас в теме
Вопрос, что будет на линуксовых и веб-клиентах, излишен, да? Очень костыльное и ограниченное решение.
10. Дмитрий Головко (golovkodv) 54 15.11.17 15:45 Сейчас в теме
Кому-то может и пригодится
11. Екатерина Бородина (zxc753) 15.11.17 17:47 Сейчас в теме
А еще можно использовать Обновлятор 1С)
12. Евгений Мадонов (madonov) 156 16.11.17 06:42 Сейчас в теме
Зачем проверять динамическое обновление каждую минуту?
Зачем писать в регистр и читать из него?
Почему нельзя выполнить эту проверку 1 раз при завершении работы системы?

Не очень понимаю зачем столько шагов. Почему не сделать так?
Процедура ПриЗавершенииРаботыСистемы()
    ОчиститьКэш1С();    
КонецПроцедуры


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

КонецПроцедуры
Показать
14. Дмитрий Головко (golovkodv) 54 16.11.17 11:10 Сейчас в теме
(12)
Пользователь не всегда корректно выходит с программы. Если по каким-либо причинам будет аварийное завершение работы, то по вашему методу кэш просто не очистится. Здесь он добавляется в очередь и при первом же корректном выходе очищает кэш с удалением из очереди.
13. Евгений Мадонов (madonov) 156 16.11.17 08:11 Сейчас в теме
Ну и вообще, надежность такого подхода несколько хромает:
Пользователь открыл 1 экземпляр программы,
Пользователь открыл 2 экземпляр программы на этом же ПК под этой же учетной записью,
Динамическое обновление - пользователь в очереди на очистку кэша,
Пользователь закрыл любой из экземпляров программы - пользователь исключен из очереди на очистку кэша, однако очистка не произошла, тк открыт другой экземпляр программы.

Справедливости ради стоит отметить, что если проверять наличие динамического обновления при завершении, то такая коллизия тоже возможна, но при ином сценарии:
Пользователь открыл 1 экземпляр программы,
Динамическое обновление,
Пользователь открыл 2 экземпляр программы на этом же ПК под этой же учетной записью,
Пользователь закрыл 1 экземпляр программы - однако очистка не произошла, тк открыт 2 экземпляр программы.
Пользователь закрыл 2 экземпляр программы - однако во время работы этого экземпляра динамического обновления не происходило и кэш не очищается.

Для того, чтобы кэш точно не вызывал проблем - его нужно очищать при каждом завершении работы, но это приведет к необоснованному замедлению старта программы.
15. Дмитрий Головко (golovkodv) 54 16.11.17 11:16 Сейчас в теме
(13)
У меня на работе для пользователей не предусмотрено открытие нескольких экземпляров 1с. Поэтому я их и не рассматривал. Но думаю можно и такой случай предусмотреть: При завершении работы просмотреть активные сеансы (функция "ПолучитьСеансыИнформационнойБазы ") для своего текущего пользователя. И запускать очистку только если сеанс текущего пользователя присутствует в единственном числе . Иначе ничего не делать.
Оставьте свое сообщение