Warning
Данная статья не претендует на оригинальность и не является конечным решением. Подходы решения задач и примеры программного кода несут исключительно обучающий характер. |
Существуют ситуации, когда нужно реализовать некий алгоритм и выполнить его в фоновом режиме. Подобных ситуаций может быть масса, а возможностей реализаций в 1С мало и все они сложные.
Ниже представлен вариант реализации длительной операции из внешней обработки. Обязательные требования: обработка должна быть добавлена в справочник ДополнительныеОтчетыИОбработки и наличие БСП v3.
Итак, поехали!
- Управляемая форма:
-
Демонстрационный код модуля внешней обработки (тут все топорно просто):
Функция СведенияОВнешнейОбработке() Экспорт ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2.1"); ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительнаяОбработка(); ПараметрыРегистрации.БезопасныйРежим = Ложь; НоваяКоманда = ПараметрыРегистрации.Команды.Добавить(); НоваяКоманда.Представление = Метаданные().Синоним; НоваяКоманда.Идентификатор = "Открыть форму"; НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыОткрытиеФормы(); НоваяКоманда = ПараметрыРегистрации.Команды.Добавить(); НоваяКоманда.Представление = "Выполнить мой алгоритм"; НоваяКоманда.Идентификатор = НоваяКоманда.Представление; НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода(); НоваяКоманда = ПараметрыРегистрации.Команды.Добавить(); НоваяКоманда.Представление = "Выполнить тест"; НоваяКоманда.Идентификатор = НоваяКоманда.Представление; НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода(); Возврат ПараметрыРегистрации; КонецФункции Процедура МояДлительнаяПроцедура() ВремяФиниша = ТекущаяДата() + 100; Пока ТекущаяДата() < ВремяФиниша Цикл Процент = 100 - (ВремяФиниша - ТекущаяДата()); Если НЕ (Процент % 10) И Процент Тогда ДлительныеОперации.СообщитьПрогресс(Процент, СтрШаблон("Задание пройдено на %1 процентов", Процент)); КонецЕсли; КонецЦикла; КонецПроцедуры Функция ВыполнитьКоманду(ИдентификаторКоманды, ПараметрыКоманды) Экспорт // поиск и выполнение запрошенной команды Если ИдентификаторКоманды = "Выполнить мой алгоритм" Тогда МояДлительнаяПроцедура(); ИначеЕсли ИдентификаторКоманды = "Выполнить тест" Тогда Сообщить("Тест пройден"); КонецЕсли; КонецФункции
-
Сама реализация запуска кода модуля внешней обработки в фоновом задании из управляемой формы:
&НаСервере Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) // получим объект обработки ВнешняяОбработка = РеквизитФормыВЗначение("Объект"); // если обработка открыта из справочника проверим заполненность ссылки Параметры.Свойство("ДополнительнаяОбработкаСсылка", ДополнительнаяОбработкаСсылка); // если пустая значит открыти из вне, нужно поискать ее в справочнике Если ДополнительнаяОбработкаСсылка.Пустая() Тогда ДополнительнаяОбработкаСсылка = Справочники.ДополнительныеОтчетыИОбработки.НайтиПоНаименованию(ВнешняяОбработка.Метаданные().Синоним); КонецЕсли; // если забыли добавить в справочник выполнить в фоне не получится :-( ДоступноВыполнениеВФоне = НЕ ДополнительнаяОбработкаСсылка.Пустая(); // получим сведения о внешней обработке СведенияОВнешнейОбработке = ВнешняяОбработка.СведенияОВнешнейОбработке(); // загрузим все идентификаторы и представления команд в таблицу формы Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода(); ТаблицаКоманд.Загрузить(СведенияОВнешнейОбработке.Команды.Скопировать(Новый Структура("Использование", Использование))); // заполним список выбора команд внешней обработки Элементы.КомандаОбработки.СписокВыбора.ЗагрузитьЗначения(ТаблицаКоманд.Выгрузить().ВыгрузитьКолонку("Представление")); КонецПроцедуры &НаСервере Процедура ВыполнитьМетодТекущегоОбъекта(ИдентификаторКоманды) ВнешняяОбработка = РеквизитФормыВЗначение("Объект"); ВнешняяОбработка.ВыполнитьКоманду(ИдентификаторКоманды, Новый Структура); КонецПроцедуры // это взято из Справочник ДополнительныеОтчетыИОбработки ФормаЭлемента &НаСервереБезКонтекста Функция НачатьВыполнениеСервернойКомандыВФоне(ВыполняемаяКоманда, УникальныйИдентификатор) ИмяПроцедуры = "ДополнительныеОтчетыИОбработки.ВыполнитьКоманду"; ПараметрыПроцедуры = Новый Структура("ДополнительнаяОбработкаСсылка, ИдентификаторКоманды, ОбъектыНазначения"); ПараметрыПроцедуры.ДополнительнаяОбработкаСсылка = ВыполняемаяКоманда.Ссылка; ПараметрыПроцедуры.ИдентификаторКоманды = ВыполняемаяКоманда.Идентификатор; ПараметрыПроцедуры.ОбъектыНазначения = ВыполняемаяКоманда.ОбъектыНазначения; НастройкиЗапуска = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор); НастройкиЗапуска.НаименованиеФоновогоЗадания = НСтр("ru = 'Дополнительные отчеты и обработки: Выполнение серверного метода обработки'"); Возврат ДлительныеОперации.ВыполнитьВФоне(ИмяПроцедуры, ПараметрыПроцедуры, НастройкиЗапуска); КонецФункции &НаКлиенте Процедура ВыполнитьКомандуВФоне(ИдентификаторКоманды) // настройки ожидания НастройкиОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтаФорма); НастройкиОжидания.ВыводитьПрогрессВыполнения = Истина; НастройкиОжидания.ВыводитьСообщения = Истина; НастройкиОжидания.ТекстСообщения = НСтр("ru = 'Выполняется обработка данных.'"); // выполнить команду ВыполняемаяКоманда = Новый Структура("Ссылка, Идентификатор, ОбъектыНазначения", ДополнительнаяОбработкаСсылка, ИдентификаторКоманды, Новый Массив); ДлительнаяОперация = НачатьВыполнениеСервернойКомандыВФоне(ВыполняемаяКоманда, ЭтаФорма.УникальныйИдентификатор); ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, Неопределено, НастройкиОжидания); КонецПроцедуры &НаСервере Функция ПолучитьИдентификаторВыбраннойКоманды() // получим выбранный идентификатор Возврат ТаблицаКоманд.Выгрузить().Найти(КомандаОбработки).Идентификатор; КонецФункции &НаКлиенте Процедура ВыполнитьКоманду(Команда) Если ПустаяСтрока(КомандаОбработки) Тогда Возврат; КонецЕсли; // получим выбранный идентификатор ИдентификаторКоманды = ПолучитьИдентификаторВыбраннойКоманды(); // начать обработку данных Если ДоступноВыполнениеВФоне Тогда ВыполнитьКомандуВФоне(ИдентификаторКоманды); Иначе ВыполнитьМетодТекущегоОбъекта(ИдентификаторКоманды); КонецЕсли; КомандаОбработки = ""; КонецПроцедуры
-
Результат:
Описание работы алгоритма:
- Получает все команды из функции "СведенияОВнешнейОбработке()";
- Отбирает только те, где "Использование = ТипКомандыВызовСерверногоМетода";
- Выводит их пользователю для запуска;
- После нажатия на команду, получает ее идентификатор;
- Выполняет запуск команды через ДлительныеОперации.ВыполнитьВФоне();
- Передает ссылку на ДополнительныеОтчетыИОбработки и идентификатор команды;
- Фоновое задание получает экземпляр обработки из справочника, подключает и запускает стандартную процедуру "ВыполнитьКоманду()";
- Выполняет передачу прогресса и сообщений;
- Выводит меню ожидания с прогрессом выполнения и сообщениями.
Плюсы использования данного подхода:
- Отсутствие какого либо другого варианта;
- По сути делает аналогичные действия, как если в справочнике дополнительных отчетов и обработок — нажать на кнопку "Выполнить";
- Выводит прогресс и сообщения;
- Вместо пустого массива в "ОбъектыНазначения" можно передать полезные данные в фоновое задание.
Ну и любят же 1Сники велосипеды)))
Не благодарите)
(2) Я имел в виду варианты запуска кода модуля в ФЗ, а за то что из обработки можно сделать регламентное задание благодарим БСП.
Ранее процент выполнения длительной операции можно было вывести только если на форме нарисовать элементы. С версии БСП 3.0 это уже не нужно или и ранее так работало?
А понял в чем дело. Использовал другой код.
Показать
Переписал на ваш метод:
Показать
Не взлетело, прогресса нет. БСП в конфе 3.0.1.314.
В процедуре, которая считает все
В статье говорится, что команда должна иметь «ВызовСерверногоМетода». А я открываю форму же через «ОткрытиеФормы». Далее по кнопке вызываю длительную операцию. Выходит команда «ОткрытиеФормы», должна дернуть другую команду «ВызовСерверногоМетода»?
Возможно дело еще в:
Попробую поменять, но думаю не в этом дело.
(6)
Команда которая должна быть выполнена в фоне, должна иметь тип: ДополнительныеОтчетыИОбработкиКлиентСервер. ТипКомандыВызовСерверногоМетода();
Код обработки можно отлаживать если, установлен параметр запуска «РежимОтладки», но правда каждый раз придется обновлять обработку в справочнике.
(7) да заработало! Как через файл, если добавить обработку в справочник, так и через внешние.
Единственный минус, мне нужно передавать параметры, когда я открываю форму.
Команда с «ВызовСерверногоМетода» используется для формирования регламентного задания. Подумаю как обойти это и будет вообще песня!
У меня также есть обработка, которая таким макаром запускает несколько потоков, но там везде был клиентский метод и прогресс не выводился. Возможно ли несколько потоков запустить таким вариантом?
Проверил на БСП 2.4.2.169 работает!
А вот на 2.3.2.51 пишет, что прогресс может выводить, а вот сообщения нет.
Посмотрел код, там тоже работает! Только нужно закомментить проверку в общем модуле «ДлительныеОперацииКлиент» процедуре «ПроверитьПараметрыОжидатьЗавершение»
Она вызывает исключение, а после комментирования все работает!
(8)
Да делал такое, НачатьВыполнениеСервернойКомандыВФоне() запускал в цикле, разделяя данные по порциям и передавал их в «ОбъектыНазначения». Собирал массив длительных операций и потом на клиенте опять в цикле передавал их в ДлительныеОперацииКлиент.ОжидатьЗавершение();
(10) не совсем понял.
Это делаем в цикле? Для чего собирать ДлительнаяОперация в массив?
(2) картинок не видно 🙁
ничего сложного, делаем поиск по ключевым словам «длительные операции» или «фоновые задания» и находим пару десятков тем на данном форуме с примерами / шаблонами и т.п.
и собственно возникает вопрос: чем данная статья отличается от десятка ей подобных?
Отсутствие какого либо другого варианта;
сильное заявление, и очевидно, неверное, т.к. вы всего лишь навсего используете бсп в части длительных операций
и это плюс? тогда еще в плюсы можно записать «обработка выполняет заданный ей алгоритм»
без это с позволения сказать «плюса» мы получим обработку бесполезную чуть менее чем полностью
не стал придираться к еще одному плюсу (третьему), как ни странно не во всех примерах фоновых заданий выводятся сообщения
Ребята, у кого получился рабочий вариант. Пришлите рыбу , пожалуйста.
(14) Держите может поможет
(15)огромное спасибо за статью и за обработку.
У меня уже была обработка, для для асинхронного выполнения , но в ней очень не хватало индикатора выполнения. Надеюсь теперь будет.
Все верно, но с готовым примером проще и быстрее.
А как сделать чтобы работало прямо из файла? (т.е. без добавления в «Дополнительные отчеты и обработки»)
P.S. На новых БСП (3.0.2 и выше)
(15) не работает, не показывает прогресс, да и интерфейс блокирует. БСП 3.0.1.351
В Процедура СообщитьПрогресс срабатывает это:
Upd: разобрался, был включен режим отладки
Кстати, вот этот фрагмент успевает за секунду назапускаться сотни раз. Надо как-то ограничить одним разом.
(7)
Код обработки можно отлаживать если, установлен параметр запуска «РежимОтладки», но правда каждый раз придется обновлять обработку в справочнике.
А можно по подробнее, как отладить?
Я в параметр запуска написал «РежимОтладки», в Конфигураторе — Отладка — Подключение — Автоматическое подключение — галочки стоят Клиентские и внешние соединения на сервере и Фоновые задания (т.о. в табличке Сервер и Тонкий клиент 2 строчки). Открыл обработку в конфигураторе, поставил точку. Добавил (обновил) обработку в справочнике Дополнительных внешних обработок, тут же нажал «Выполнить» — но в отладку не попадает.
ЧЯДНТ?
(19) воспользоваться поиском по сайту (внешняя обработка длительные операции БСП)