Прогресс бар 8.2


Данный приём позволяет показать текущее состояние выполнения серверного кода пользователю, запустившего его на выполнение.

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

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

Имея 4 модуля ксПрогрессБар, ксПрогрессБарВызовСервера, ксПрогрессБарКлиент, ксПрогрессБарКлиентСервер (которые можно достать из cf файла) функционал прогресса будет выглядеть примерно так:

1. Код модуля клиента

Основная идея заключается в том, что серверный код мы выполняем фоновым заданием ВыполнениеВФоне.ТестПрогрессБара. И при этом, подключив обработчик ожидания СобратьИнформациюХодаВыполнения, начинаем сбор состояния, пока метод ксПрогрессБарКлиент.ПоказатьСостояние не вернёт флаг о завершении фонового задания.

&НаКлиенте
Процедура Тест(Команда)

    ТестНаСервере();

    Если ВыполнятьВФоне() Тогда
       
ПодключитьОбработчикОжидания(«СобратьИнформациюХодаВыполнения», ВремяОткликаСбораИнфорамацииХодаВыполнения());
    КонецЕсли;

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

Процедура ТестНаСервере()

    Если ВыполнятьВФоне() Тогда

        Доступность = Ложь;

        ФоновыеЗадания.Выполнить(«ВыполнениеВФоне.ТестПрогрессБара», , УникальныйИдентификатор, НСтр(«ru = ‘Тест прогресс бара'»));

    Иначе

        ВыполнениеВФоне.ТестПрогрессБара();

    КонецЕсли;

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

&НаКлиентеНаСервереБезКонтекста
Функция ВыполнятьВФоне()

    Возврат НЕ ксКэшНаСеанс.ИнформационнаяБазаФайловая();

КонецФункции

&НаКлиенте
Процедура СобратьИнформациюХодаВыполнения()

    Если НЕ ксПрогрессБарКлиент.ПоказатьСостояние(УникальныйИдентификатор) Тогда
       
ОтключитьОбработчикОжидания(«СобратьИнформациюХодаВыполнения»);
       
Доступность = Истина;
    КонецЕсли;

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

&НаКлиенте
Функция ВремяОткликаСбораИнфорамацииХодаВыполнения()

    Возврат 1;

КонецФункции

2. Код модуля сервера (основная часть вашего кода)

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

Процедура ТестПрогрессБара() Экспорт

    количествоИтераций = 2000000;

    текстСообщения = НСтр(«ru = ‘Тест прогресс бара'»);
   
пояснение = НСтр(«ru = ‘Пустой цикл для тестирования'»);
   
общееКоличество = количествоИтераций;
   
ц = 0;

    Для цИтератор = 1 По количествоИтераций Цикл

        ксПрогрессБар.УвеличитьСчетчикИУстановитьСостояние(ц, общееКоличество, текстСообщения, пояснение);

        // Основной код.

    КонецЦикла;

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

3. Результат

Итогом будет вот такой прогресс бар:

4. Заключение

Минусы:

-данный функционал получилось реализовать только для тонкого клиента. Хотя в основном для отрисовки прогресса используется типовой метод «Состояние».

Замечания:

-отладку фонового задания можно включить так:

-или, решением такой проблемы, может быть разработка дополнительного режима отладки, после включения которого, код будет выполняться не в фоне. Как пример, можно модернизировать метод ВыполнятьВФоне:

&НаКлиентеНаСервереБезКонтекста
Функция ВыполнятьВФоне(пТестирование)

    Возврат НЕ пТестирование
        И НЕ ксКэшНаСеанс.ИнформационнаяБазаФайловая();

КонецФункции

Плюсы:

+пользователь не только видит прогресс, но и может свободно пользоваться базой.

24 Comments

  1. DoctorRoza

    + за информацию однозначно, может пригодится! 🙂

    Добавьте вариант решения второго минуса, хотя бы наброски!

    Reply
  2. ksai

    (1) DoctorRoza,

    Добавьте вариант решения второго минуса, хотя бы наброски!

    А галочка «Фоновые задания» в настройках отладки в конфигураторе чем не устраивает? Ну и ключ -debug в строке запуска сервера.

    Reply
  3. Soloist

    (2) ksai, спасибо. Только что для себя открыл этот способ: Меню Отладка -> Подключение -> Автоматическое подключение -> Фоновые задания. http://screencast.com/t/eT0vgE9t

    Reply
  4. ksai

    (3)

    Да не за что 🙂 Я думал, факт общеизвестный.

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

    1) Строка подключения инф. базы конфигуратора и строка подключения фонового задания должны совпадать посимвольно. Например: если конфигуратор подключается через строку «Srvr=»server:1641″;Ref=»BASE»;«, а фоновое задание через «Srvr=»server»;Ref=»BASE»;«, то отладка не подключится, хоть ты убейся.

    2) В справочнике «Пользователи» на момент запуска фонового задания не должно быть элемента с пустым кодом, кроме «пустого» пользователя, которого система создает автоматически для выполнения фоновых заданий, иначе вот на этой функции «Функция ПроверитьПользователяПоКоду(ИмяПользователя)» сеанс фонового задания вывалится с исключением без всяких сообщений.

    P.S. Проверено на УПП 1.3

    Reply
  5. ksai

    (3)

    И, кстати, в свете последних событий:) стоит, наверно, изменить текст про минус в публикации.

    Reply
  6. Evg-Lylyk

    Еще один недостаток то что это фоновые задания следовательно без изменения конфы никак!!!

    Вот по теме публикации: Эффективная индикация в 8.2

    Reply
  7. treedo

    Большое спасибо. Давно ломал голову как это реализовать в тонком клиенте)))

    Reply
  8. Soloist

    (4) ksai, спасибо ещё раз. Попозже поправлю.

    (6) Evg-Lylyk, даже и не думал искать по теме индикация… Извиняюсь. Да, конфу придётся изменить, поэтому старался минимизировать количество строк кода, инкапсулировав всё что можно, для пользования этим методом. Надеюсь удалось.

    Reply
  9. ~gekK@~

    да уж…вроде задача должна решаться штатными методами, но…

    Reply
  10. ZOOBR

    Идея вполне себе рабочая. Мысли в эту сторону были, но руки не дошли, так что автору+.

    (9) А чем уж не штатный метод.) Добавить задание в конфигураторе по-моему не проблема, тем более, что обычно когда до таких «удобняков» дело доходит конфа уже изменена. А уж если вспомнить про всякие там XDTO и SOAP, то правка конфы это уже обыденность. Отладку тоже минусом врядли можно считать, скорее как и было озвучено просто нюансом.

    (6) Там реализация сложновата не везде подойдет, хотя анализ приведён весьма показательный. Сляпать фоновое задание я думаю проще.

    Правда как я понял без ложки дёгтя таки не обошлось. Проблема с реализацией будет в том случае если допустить, что прогресс-бар будет запускаться сразу от нескольких пользователей. Как быть в этом случае? Вот про это стоило бы упомянуть в статье.

    Reply
  11. Soloist

    (10) ZOOBR, не понятно что за ложка? Прогресс рисует типовой метод «Состояние» и если операции непересекаемые, то вообще всё шикарно. Создадутся столько фоновых заданий сколько нужно, а они уж по уникальному идентификатору найдут своего пользователя. Допустим пакетное проведение документов по Организации1 для первого пользователя, и проведение по Организации2 для другого нам дадут вполне хороший результат. Если уж данные пересекаются, т.е. первый проводит по всем документам, а второй хочет по Организации2, то тут уж надо заботиться о захвате данных… но это не проблема прогресс бара… В худшем случае они оба увидят прогресс бар, но данные будут плохие. В хорошем, второму пользователю надо сказать — «подождите… данные захвачены другим пользователем».

    Reply
  12. pbazeliuk

    Идея хорошая, но как-то запутано все. Сделал проще для УТ 11 без изменения конфигурации (для SQL версии). Выложу сегодня в паблик.

    Reply
  13. Soloist

    (12) Baza, чем проще — тем лучше:)

    Reply
  14. CaSH_2004

    В публикации уточнение что работает только для тонкого, т.е. для ВЕБ не сработает? Проверено?

    Reply
  15. Soloist

    (14) CaSH_2004, вы так интересно построили предложение-вопрос:)

    Я был уверен, что работает, т.к. чему там не работать… Ради вас проверил на win 8)) Работает. И очень даже красиво http://screencast.com/t/N5u3ZHvrTRr

    Reply
  16. CaSH_2004

    (15) Блогадарю, очень красиво, я так понимаю вы тоже пользуетесь Google Chrome вместо Internet Explorer? Просто по привычке или не устраивает что-то конкретное? Вопрос к тому что я долго не мог нормально запустить WEB базу нормально т.к. Explorer вис и сыпал кучей ошибок даже при авторизации, а при проведении группы документов так вообще полное повисание, а Chrome выполнил не задумываясь даже. Так что мы выбрали его для постоянного пользования.

    Reply
  17. Soloist

    (16) CaSH_2004, раньше не устраивала актуальность, Chrome он ведь сам обновляется… а сейчас с него не слезу, т.к. у меня синхронизация закладок и паролей на нём, да и привык уже к нему.

    Всё зависит от версии IE, у 1С есть минимальные требования к браузеру. На IE10 так же всё хорошо.

    Reply
  18. ddiimmaann

    Плюс за идею!

    Прогресс-бар есс-но нужен, если выполняемое задание имеет значительную протяженность во времени. В жизни пользователи (а особенно мы, программисты, во время отладки) — не дожидаемся окончания процесса. Если закрыть «форму с кнопкой» к которой прикручен обработчик ожидания — то задание в фоне остается висеть и выполняется до конца. Предлагаю добавить в форму что-то типа:

    &НаКлиенте
    Процедура ПередЗакрытием(Отказ, СтандартнаяОбработка)
    
    Если ФоновоеЗаданиеАктивно() Тогда
    Ответ = Вопрос(«Выполнение не окончено! Отменить задание?», РежимДиалогаВопрос.ДаНет , , КодВозвратаДиалога.Нет, «Внимание!»);
    Если Ответ=КодВозвратаДиалога.Да Тогда
    ОтменитьЗадание();
    Иначе
    Отказ = Истина;
    КонецЕсли;
    КонецЕсли;
    
    КонецПроцедуры
    
    &НаСервере
    Функция ФоновоеЗаданиеАктивно()
    
    НашПроцесс = ксПрогрессБар.НайтиЗадание(УникальныйИдентификатор);
    
    Если НашПроцесс=Неопределено Тогда Возврат Ложь; КонецЕсли;
    
    Возврат НашПроцесс.Состояние=СостояниеФоновогоЗадания.Активно;
    
    КонецФункции
    
    &НаСервере
    Процедура ОтменитьЗадание()
    
    НашПроцесс = ксПрогрессБар.НайтиЗадание(УникальныйИдентификатор);
    
    Если НашПроцесс=Неопределено Тогда
    Возврат;
    Иначе
    НашПроцесс.Отменить();
    КонецЕсли
    
    КонецПроцедуры

    Показать

    Reply
  19. Soloist

    (18) ddiimmaann, спасибо. Скоро добавлю и обновлю.

    Reply
  20. ddiimmaann

    И еще, как идею, озвучу такую:

    Для

    1. упрощения интеграции

    2. возможности использовать в командах (они запускаются вне контекста формы)

    Я создал общую форму, в которую перенес часть методов из «1. Код модуля клиента».

    В итоге удалось добиться вот такой минимизации (на примере команды)

    В Модуле команды:

    &НаКлиенте
    Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
    
    ПараметрыФормы = Новый Структура;
    ПараметрыФормы.Вставить(«ИмяПроцедуры», «ВыполнениеВФоне.ТестПрогрессБара»);
    ПараметрыФормы.Вставить(«НаименованиеЗадачи», «Выполняется сложное задание. Придется подождать.»);
    ОткрытьФорму(«ОбщаяФорма.ФормаОтображенияПрогрессаВыполнения», ПараметрыФормы);
    
    КонецПроцедуры

    Показать

    При таком подходе задача по управлению фоновым процессом иожно возложить на форму

    -процесс запускается с ее идентификатором

    -все обработки и проверки по завершению незаконченного процесса — можно написать 1 раз

    -в форме можно реализовать проверки на тип платформы (в клиент-серверном — запускать в фоне, в файл серверном использовать другой механизм — если таковой имеется, я не в курсе 🙂 )

    Reply
  21. ddiimmaann
    Reply
  22. Al-X

    + !!! Вот это точно пригодиться.

    Reply
  23. dj_serega

    В cf нашел ошибку:

    #Если Клинет Тогда

    Состояние(пТекстСообщения, пПрогресс, пПояснение);

    #КонецЕсли

    Reply
  24. Soloist

    (23) dj_serega, спасибо большое.

    Исправил. Обновил cf.

    Reply

Leave a Comment

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