Передача данных между фоновой задачей и родителем

1. user589938_eq2005 19.06.18 15:36 Сейчас в теме
Здравствуйте!
Пытаюсь овладеть секретами Фоновых задач.
Создал общий модуль не глобальный, для работы на сервере, с единственной процедурой:
&НаСервере
Процедура СборИнформации(Адрес) Экспорт
	Спр=Справочники.ПНШ_ДляФоновых;
	Нов=Спр.СоздатьЭлемент();
	БуферСвязи=Новый Структура("Текст,Значение,Конец","",0,Ложь);
	Попытка
		Нов.Наименование=Адрес;
		НовСтр=Нов.Лог.Добавить();
		НовСтр.Строчка="адрес="+Адрес+" это для хранилища: "+ЭтоАдресВременногоХранилища(Адрес);
		НовСтр=Нов.Лог.Добавить();
		НовСтр.Строчка=БуферСвязи.Текст+БуферСвязи.Значение+" "+БуферСвязи.Конец;
		БуферСвязи.Текст="Нас много: ";
		БуферСвязи.Значение=0;
		НовСтр=Нов.Лог.Добавить();
		НовСтр.Строчка=БуферСвязи.Текст+БуферСвязи.Значение+" "+БуферСвязи.Конец;
		Для х=0 по 3 цикл
			Тек=ТекущаяДата();
			Пока ТекущаяДата()-Тек<=3 Цикл
				// здесь можно делать что-нибудь полезное
			КонецЦикла;
			БуферСвязи.Значение=х;
			НовСтр=Нов.Лог.Добавить();
			НовСтр.Строчка="Значение="+х+"   "+ПоместитьВоВременноеХранилище(БуферСвязи,Адрес);
		КонецЦикла;
	Исключение
		Инфо=ИнформацияОбОшибке();
		НовСтр=Нов.Лог.Добавить();
		НовСтр.Строчка="Ошибочка вышла: "+Инфо.Описание;
		НовСтр=Нов.Лог.Добавить();
		НовСтр.Строчка="  ("+Инфо.НомерСтроки+"): "+Инфо.ИсходнаяСтрока;
		НовСтр=Нов.Лог.Добавить();
		НовСтр.Строчка="  "+Инфо.ИмяМодуля;
	КонецПопытки;
	Нов.Записать();
	БуферСвязи.Конец=Истина;
	ПоместитьВоВременноеХранилище(БуферСвязи,Адрес);
КонецПроцедуры
Показать

Затем создал обработку с управляемой формой с единственной кнопкой:
&НаСервере
Процедура ЗапускПроцессаНаСервере(Адрес,СтрОтладки)
	Пар=Новый Массив;
	Пар.Добавить(Адрес);
	БББ=ПолучитьИзВременногоХранилища(Адрес);
	ФЗ=ФоновыеЗадания.Выполнить("Фоновые.СборИнформации",Пар,"СборИнформации"+ТекущаяДата(),"Мой расчёт");
	БББ=ПолучитьИзВременногоХранилища(Адрес);
КонецПроцедуры

&НаКлиенте
Процедура ЗапускПроцесса(Команда)
	СтрОтладки=Новый Массив;
	//БуферСвязи=Новый Структура("Текст,Значение,Конец","Нас мало: ",-1,Ложь);
	БуферСвязи=Неопределено;
	АдресДанных=ПоместитьВоВременноеХранилище(БуферСвязи,ЭтаФорма.УникальныйИдентификатор);
	Сообщить("Адрес данных: "+АдресДанных);
	ЗапускПроцессаНаСервере(АдресДанных,СтрОтладки);
	Для каждого Стр Из СтрОтладки Цикл
		Сообщить(Стр);
	КонецЦикла;
	Сч=0;
	Флаг=Ложь;
	Пока НЕ Флаг И Сч<20 Цикл
		Зап=Справочники.ПНШ_ДляФоновых.НайтиПоНаименованию(АдресДанных);
		БуферСвязи=ПолучитьИзВременногоХранилища(АдресДанных);
		//Состояние(БуферСвязи.Текст+БуферСвязи.Значение+"     Сч="+Сч);
		Если БуферСвязи=НеопределеноТогда
			Сообщить("Ерунда...");
		Иначе
			Сообщить("Сч="+Сч+". Адрес="+Зап.Наименование+".  Колво="+Зап.Лог.Количество());
			Сообщить(БуферСвязи.Текст+БуферСвязи.Значение+"     Сч="+Сч);
			Флаг=БуферСвязи.Конец;
		КонецЕсли;
		Сч=Сч+1;
		Тек=ТекущаяДата();
		Пока ТекущаяДата()-Тек<=2 Цикл
			// здесь можно делать что-нибудь полезное
		КонецЦикла;
	КонецЦикла;
КонецПроцедуры
Показать

При запуске процедуры ЗапускПроцесса что-то происходит, но при этом:
1. Переменная БуферСвязи так и остаётся неопределённой (через каждые 2 секунды выдаётся "Ерунда..."
2. Судя по содержимому справочника, фоновое задание таки запускается и своё отрабатывает.
3. Адрес замечательно передаётся в фоновое задание.

А теперь вопрос. Почему БуферСвязи на клиенте не получает ничего, хотя в фоновом задании в него что-то пишется?
По идее, если задания выполняются параллельно (иначе какой же это фон?), тогда где-то на 20 секунде клиент-родитель должен получить нормальную запись в БуфереСвязи, а этого не происходит.
"Доктор, что я делаю не так?" (с) анек....
+
По теме из базы знаний
Ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
4. Boneman 298 19.06.18 16:10 Сейчас в теме
(1) не надо в цикле по счетчику получать из временного хранилища.
Надо использовать обработчик ожидания.
т.е. идея такая, по кнопке с формы запускаем выполнение фонового задания. В него передаем адрес, и там все отрабатывает и во временное хранилище помещается
&НаКлиенте
Процедура ЗагрузитьВФоне(Команда)
	Если ТаможняДаетДобро() тогда
		Элементы.Загрузить.Доступность = Ложь;
		Элементы.ГруппаИнформация.Видимость=Ложь;
		Элементы.ДлительнаяОперация.Видимость=Истина;
		КлючЗадания = "Грузим "+Строка(Объект.Организация);//"ВУРШЕЛХАПИЛЛО";
		Если ЕстьАктивныеЗадания(КлючЗадания) тогда
			Сообщить("Нет, уже кто-то грузит ваше юр.лицо");
		Иначе
			ЗапускФЗ(АдресХранилища, КлючЗадания);	
		КонецЕсли;
		ПодключитьОбработчикОжидания("ОбновитьСписокФоновыхЗаданий", 2);
	КонецЕсли;
КонецПроцедуры
Показать

а по обработчику ожидания
обходим наши РЗ.
и пытаемся извлечь из временного хранилища
	Месаги = ПолучитьИзВременногоХранилища(АдресХранилища);
	Если Месаги <> неопределено тогда


полный текст (кусок из моей наработки, половина кода там выкинуть надо, но смысл думаю будет понятен)
&НаКлиенте
Функция ОбновитьСписокФоновыхЗаданий()
	//КлючЗадания = "ВУРШЕЛХАПИЛЛО";
	КлючЗадания = "Грузим "+Строка(Объект.Организация);
	Если НЕ ЕстьАктивныеЗадания(КлючЗадания) тогда
		Элементы.Загрузить.Доступность = Истина;
		Элементы.ДлительнаяОперация.Видимость=Ложь;
	КонецЕсли;
		ФоновыеЗаданияТЗ.Очистить();
		ПолучитьСписокЗаданий(КлючЗадания, АдресХранилища);
//	КонецЕсли;

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

&НаСервере
Функция ПолучитьСписокЗаданий(КлючЗадания, АдресХранилища)
	
	НайденныеЗадания = ФоновыеЗадания.ПолучитьФоновыеЗадания(Новый Структура("Ключ", КлючЗадания));
	
	Если НайденныеЗадания.Количество() = 0 Тогда Возврат Ложь; КонецЕсли;

    //Фоновое = НайденныеЗадания[0];

	Для Каждого Фоновое из НайденныеЗадания Цикл
	
	НоваяСтрока = ФоновыеЗаданияТЗ.Добавить();
	
	РегламентноеЗадание = Фоновое.РегламентноеЗадание;
	Если РегламентноеЗадание <> Неопределено Тогда
		Строка = РегламентноеЗадание.Метаданные.Представление();
		Если РегламентноеЗадание.Наименование <> "" Тогда
			Строка = Строка + ":" +	РегламентноеЗадание.Наименование;
		КонецЕсли;
			
		НоваяСтрока.Задание = Строка;
	КонецЕсли;
			
	НоваяСтрока.Наименование = Фоновое.Наименование;
	НоваяСтрока.Ключ = Фоновое.Ключ;
	НоваяСтрока.Метод = Фоновое.ИмяМетода;
	НоваяСтрока.Состояние = Фоновое.Состояние;
	НоваяСтрока.Начало = Фоновое.Начало;
	НоваяСтрока.Конец = Фоновое.Конец;
	НоваяСтрока.Сервер = Фоновое.Расположение;
		
	Если Фоновое.ИнформацияОбОшибке <> Неопределено Тогда
		ТекстОшибки = Фоновое.ИнформацияОбОшибке.ИмяМодуля+Символы.ПС+Фоновое.ИнформацияОбОшибке.ИсходнаяСтрока+Символы.ПС+Фоновое.ИнформацияОбОшибке.НомерСтроки+Символы.ПС+Фоновое.ИнформацияОбОшибке.Описание+Символы.ПС+?(Фоновое.ИнформацияОбОшибке.Причина=Неопределено, "", Фоновое.ИнформацияОбОшибке.Причина.Описание);
		//НоваяСтрока.Ошибки = Фоновое.ИнформацияОбОшибке.Описание;
		НоваяСтрока.Ошибки = ТекстОшибки;
	КонецЕсли;
		
	НоваяСтрока.Идентификатор = Фоновое.УникальныйИдентификатор;
	НоваяСтрока.СостояниеЗадания = Фоновое.Состояние;
	Если Фоновое.Состояние = СостояниеФоновогоЗадания.Активно Тогда
		МассивСообщений = Фоновое.ПолучитьСообщенияПользователю(Истина);
		Если МассивСообщений <>неопределено тогда
			Для Каждого Сообщение Из МассивСообщений Цикл
            	Если Строка(Сообщение.ИдентификаторНазначения) = "00000000-0000-0000-0000-000000000000" Тогда
                	Сообщить(Сообщение.Текст);
            	Иначе
                	ОбщегоНазначенияКлиентСервер.СообщитьПользователю(Сообщение.Текст, Сообщение.КлючДанных, Сообщение.Поле, Сообщение.ПутьКДанным);
            	КонецЕсли;
        	КонецЦикла;
			
	    КонецЕсли;
	КонецЕсли;
	КонецЦикла;

	
	// из регламентного, пока оно корректно не отработает, хрен что наружу выйдет, даже через врем.хранилище
	// поэтому будем ее выпасать, если есть что оттуда взять, тогда и возьмем.
// Работает, но закоментил т.к. вызываю на сервере без контекста, чтобы форма не перерисовывалась.
	Месаги = ПолучитьИзВременногоХранилища(АдресХранилища);
	Если Месаги <> неопределено тогда
		Если ТипЗнч(Месаги) = Тип("ТаблицаЗначений") тогда
			
		Если Месаги.Количество()>0 тогда
			//Элементы.ГруппаИнформация.Видимость=Истина;
			Если Информация.Количество()<> Месаги.Количество() тогда
				Информация.Очистить();
				Для Каждого Месадж из Месаги цикл
					СтрИнформация = Информация.Добавить();
					СтрИнформация.СтрокаСообщения = Месадж.ИнформацияСтрока;
				КонецЦикла;
				ВывестиПортянкуСервер();
				//ВывестиПостроитель(Месаги, ТабДок);
			КонецЕсли;
		КонецЕсли;
		
		иначеесли ТипЗнч(Месаги) = Тип("Строка") тогда
			ТЗ = ЗначениеИзСтрокиXML(Месаги);
			ВывестиПостроитель(ТЗ, Табдок);
			Элементы.ТабДок.Видимость = Истина;
			Элементы.ТекстДок.Видимость=Ложь;
		КонецЕсли;
		ОперацияЗавершена = Истина;
			
	КонецЕсли;
КонецФункции
Показать

обработчик ожидания надо отключать, после отработки требуемого ФЗ.
+
2. VmvLer 19.06.18 15:43 Сейчас в теме
код корявый на мой взгляд

чисто интуитивно - пока фоновое задание не завершено значение переменной БуферСвязи не будет помещено в хранилище по адресу возврата.

Иными словами клиент увидит БуферСвязи только после выполнения фонового задания.

Вообще БСП уже давно предлагает решение подобных задач.
Причем, эти решения легко тиражировать в свои вызовы.
Мастерить свой костыль конечно можно, но зачем?
+
3. user589938_eq2005 19.06.18 16:00 Сейчас в теме
(2)
код корявый
У меня нет возможности вести отладку на сервере, приходится изголяться.

(2)
чисто интуитивно - пока фоновое задание не завершено значение переменной БуферСвязи не будет помещено в хранилище по адресу возврата
А для чего мне тогда фоновое задание? Декларируется, насколько я понимаю, параллельная обработка, или я что-то не так понимаю...

(2)
Вообще БСП уже давно предлагает решение подобных задач.

Какой из пунктов это предлагает?
Содержание
•1 Подсистемы 1С БСП
•1.1 1.Базовая функциональность
•1.2 2.Работа в модели сервиса
•1.3 3. Адресный классификатор
•1.4 4. Анализ журнала регистрации
•1.5 5. Анкетирование
•1.6 6. Банки
•1.7 7. Бизнес-процессы и задачи
•1.8 8. Валюта
•1.9 9. Варианты отчетов
•1.10 10. Версионирование объектов
•1.11 11. Взаимодействия
•1.12 12.Групповое изменение объектов
•1.13 13. Даты запрета изменения
•1.14 14. Дополнительные отчеты и обработки
•1.15 15. Завершение работы пользователей
•1.16 16. Заметки пользователя
•1.17 17. Запрет редактирования реквизитов объектов
•1.18 18. Защита персональных данных
•1.19 19. Информационный центр
•1.20 20. Информация при запуске
•0.1 21. Календарные графики
•0.2 22. Контактная информация
•0.3 23. Контроль динамического обновления конфигурации
•0.4 24. Напоминания пользователя
•0.5 25. Настройка порядка элементов
•0.6 26. Настройки программы
•0.7 27. Обмен данными
•0.8 28. Обмен сообщениями
•0.9 29. Обновление версии ИБ
•0.10 30. Обновление конфигурации
•0.11 31. Организации
•0.12 32. Отправка SMS
•0.13 33.Оценка производительности
•0.14 34. Печать
•0.15 35. Полнотекстовый поиск
•0.16 36. Получение файлов из Интернет
•0.17 37. Пользователи
•0.18 38. Префиксация объектов
•0.19 39. Присоединенные файлы
•0.20 40. Проверка легальности получения обновлений
•0.21 41. Работа с почтовыми сообщениями
•0.22 42. Работа с файлами
•0.23 43. Рассылка отчетов
•0.24 44. Регламентные задания
•0.25 45. Резервное копирование ИБ
•0.26 46. Свойства
•0.27 47. Структура подчиненности
•0.28 48. Управление доступом
•0.29 49. Управление итогами
•0.30 50. Файловые функции
•0.31 51. Физические лица
•0.32 52. Электронная цифровая подпись
•1 Заключение

Показать

Кроме того, хочется разобраться как это работает, а не просто "читать заученные заклинания".

В прочем, исходная задача такая: отслеживать прогресс выполнения задачи на сервере, при этом иметь возможность продолжать работать в системе.
+
5. user589938_eq2005 20.06.18 09:10 Сейчас в теме
Спасибо за ответы, однако ответа на вопрос я так и не получил. Правильно ли я понимаю, что пока фоновое задание работает, то наружу от него ничего не дождаться, кроме как если оно будет писать в файл или в базу? Через хранилище же ничего в процессе не передать - только по окончании работы фонового задания, я правильно понимаю?
+
6. t.v.s. 111 20.06.18 09:54 Сейчас в теме
(5) В фоновом задании вызываете Сообщить(), в основном коде по обработчику ожидания ПолучитьСообщенияПользователю()

Вот кусочек кода из моей обработки
Для Каждого Задача из СписокЗадач цикл
		//Получаем сообщения и состояния фоновых заданий
		НайденныеЗадания = ФоновыеЗадания.ПолучитьФоновыеЗадания(Новый Структура("УникальныйИдентификатор", Задача.Идентификатор));
		Для каждого Задание из НайденныеЗадания цикл
			МассивСообщений = Задание.ПолучитьСообщенияПользователю(Истина);
			Для Каждого Сообщение из МассивСообщений Цикл
+
7. Boneman 298 21.06.18 16:50 Сейчас в теме
(5)
только по окончании работы фонового задания, я правильно понимаю?

да,
именно поэтому результат из хранилища надо обработчиком ожидания "выпасать".
В моем примере кода, этот момент даже откомментирован
+
8. user589938_eq2005 22.06.18 15:45 Сейчас в теме
Внимание! Тема сдана в архив

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот