Запуск фонового задания во внешней обработке. Отключение предупреждений защиты от опасных действий в фоновом задании

Как запустить фоновое задание из модуля внешней обработки используя БСП. Как отключить безопасный режим и сообщения защиты от опасных действий независимо от профиля безопасности пользователя в фоновом задании во внешней обработке.

1. Как запустить фоновое задание из модуля внешней обработки используя БСП

 

После тщетных попыток запустить в фоне процедуру модуля объекта внешней обработки, я все-таки решил глубже копнуть все механизмы длительных операций БСП. Все процедуры выполнения кода в фоне из подсистемы "Длительные операции" работают на сервере. То есть все происходит так: берется внешняя обработка, хранящаяся в справочнике "ДополнительныеОтчетыИОбработки", разворачивается на сервере (вот тут ключевой момент) и из этого экземпляра обработки выполняются указанные процедуры / функции модуля объекта (см. процедуру "ЗапуститьФоновоеЗаданиеСКонтекстомКлиента" модуля "ДлительныеОперации" БСП 3.х). Если вы вызываете ту же самую обработку из "файл-открыть", то БСП тупо пытается запустить указанные методы из обработки на сервере, в то время как обработка находится на клиенте.

 

Выходом было создать копию внешней обработки на сервере и запустить процедуру ее (копии) модуля объекта в фоне. Для этого, при открытии формы я помещал обработку во временное хранилище и тут же создавал копию на сервере в временном файле. Имя файла на сервере хранил в реквизите формы.

&НаКлиенте
Процедура ПриОткрытии(Отказ)

Если ЭтоВнешняяОбработка() Тогда
ОписаниеОповещения = Новый ОписаниеОповещения("ОбработатьРезультатПомещенияФайлаОбработки", ЭтотОбъект);
НачатьПомещениеФайлов(ОписаниеОповещения, ИмяФайлаОбработки(), Ложь, УникальныйИдентификатор);
КонецЕсли;

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

&НаКлиенте
Процедура ОбработатьРезультатПомещенияФайлаОбработки(ПомещенныеФайлы, ОбработчикЗавершения) Экспорт

Если ПомещенныеФайлы <> Неопределено Тогда
// Создаем копию текущией обработки на сервере
ХранениеФайлаОбработки = КопияОбработкиНаСервере(ПомещенныеФайлы[0].Хранение);
КонецЕсли;

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

&НаСервере
Функция КопияОбработкиНаСервере(Хранение)

Результат = ПолучитьИмяВременногоФайла();
ДвоичныеДанные = ПолучитьИзВременногоХранилища(Хранение);
ДвоичныеДанные.Записать(Результат);

Возврат Результат;

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

&НаСервере
Функция ИмяФайлаОбработки()

Возврат РеквизитФормыВЗначение("Объект").ИспользуемоеИмяФайла;

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

&НаСервере
Функция ЭтоВнешняяОбработка()

ЧастиИмени = СтрРазделить(РеквизитФормыВЗначение("Объект").Метаданные().ПолноеИмя(), ".");
Возврат (ВРег(ЧастиИмени[0]) = "ВНЕШНЯЯОБРАБОТКА")

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

Ну вот, собственно и все. Осталось только правильно вызвать процедуру из модуля объекта копии обработки на сервере.

&НаКлиенте
Процедура НачатьВыполнениеФоновогоЗадания()

// Указываете свои параметры выполнения фонового задания....

ОповещениеОПрогрессеВыполнения = Новый ОписаниеОповещения("<ОповещениеОПрогрессеВыполнения>", ЭтотОбъект);

ДлительнаяОперация = НачатьВыполнениеФоновогоЗаданияНаСервере();

ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
ПараметрыОжидания.ТекстСообщения = <...>;
ПараметрыОжидания.ВыводитьПрогрессВыполнения = <...>;
ПараметрыОжидания.ОповещениеОПрогрессеВыполнения = ОповещениеОПрогрессеВыполнения;
ПараметрыОжидания.ОповещениеПользователя.Показать = <...>;
ПараметрыОжидания.ВыводитьОкноОжидания = <...>;
ПараметрыОжидания.ВыводитьСообщения = <...>;

ОповещениеОЗавершении = Новый ОписаниеОповещения("<ОповещениеОЗавершении>", ЭтотОбъект);
ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, ОповещениеОЗавершении, ПараметрыОжидания);

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


&НаСервере
Функция НачатьВыполнениеФоновогоЗаданияНаСервере()

ПараметрыВыполненияОбработки = Новый Структура;
// Здесь указываете параметры, передаваемые в процедуру, выполняемую в фоне
// ....
// ...

// Остальной код можно оставлять, как есть, не забыв указать имя фоновой процедуры и ее описание

ЭтоВнешняяОбработка = ЭтоВнешняяОбработка();
ИмяОбработки = ?(ЭтоВнешняяОбработка, ХранениеФайлаОбработки, РеквизитФормыВЗначение("Объект").Метаданные().ПолноеИмя());

ПараметрыЗадания = Новый Структура;
ПараметрыЗадания.Вставить("ИмяОбработки",  ИмяОбработки);
ПараметрыЗадания.Вставить("ИмяМетода",   "<Имя процедуры в модуле объекта>");
ПараметрыЗадания.Вставить("ПараметрыВыполнения", ПараметрыВыполненияОбработки);
ПараметрыЗадания.Вставить("ЭтоВнешняяОбработка", ЭтоВнешняяОбработка);

ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор);
ПараметрыВыполнения.НаименованиеФоновогоЗадания = НСтр("ru = '<Описание вашего фонового задания>'");
ПараметрыВыполнения.ЗапуститьВФоне = Истина;
ПараметрыВыполнения.Вставить("ИдентификаторФормы", УникальныйИдентификатор);

ВыполняемыйМетод = "ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки"; // Выполняем процедуру из модуля объекта
Возврат ДлительныеОперации.ВыполнитьВФоне(ВыполняемыйМетод, ПараметрыЗадания, ПараметрыВыполнения);

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

 

2. Как отключить безопасный режим и сообщения защиты от опасных действий независимо от профиля безопасности пользователя в фоновом задании во внешней обработке

 

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

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

Выглядит это так:

Функция ОбработкаДанных(...) Экспорт

...

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

Процедура ОбработкаДанныхВФоне(Параметры, АдресРезультата) Экспорт

ЧастиИмени = СтрРазделить(ЭтотОбъект.Метаданные().ПолноеИмя(), ".");
ЭтоВнешняяОбработка = (ВРег(ЧастиИмени[0]) = "ВНЕШНЯЯОБРАБОТКА");
Если ЭтоВнешняяОбработка Тогда
ОбработкаОбъект = ВнешниеОбработки.Создать(ЭтотОбъект.ИспользуемоеИмяФайла, Ложь, ОбщегоНазначения.ОписаниеЗащитыБезПредупреждений());
Результат = ОбработкаОбъект.ОбработкаДанных(...);
Иначе
Результат = ОбработкаДанных(...);
КонецЕсли;

ПоместитьВоВременноеХранилище(Результат, АдресРезультата);

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

То есть, я создал еще один экземпляр самой себя без контроля прав (не в безопасном режиме и с отключением предупреждений защиты от опасных действий).

Пример использования, созданный из обработки демонстрационной конфигурации БСП прилагается (создавалась на платформе 8.3.13.1513, совместима с любой платформой 8.3, которая поддерживает БСП 3.0 и старше)

 

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

 

19 Comments

  1. jONES1979

    «капнуть» -> «копнуть»

    Reply ↓
  2. jONES1979

    (2) «не грамотный» -> «неграмотный»

    Но теперь-то грамотный! А грамотность — это первое впечатление! И отсутствие подсознательного раздражения от читаемого текста.

    …

    Я забыл что оказывается здесь нельзя почистить комменты. Ну тогда сорри, в другой раз в личку напишу)

    Reply ↓
  3. BenGunn

    (3) Мне гораздо больше нравится мысль, что подобное еще никто не делал (если даже и сделал, то не говорит об этом).

    Reply ↓
  4. BenGunn

    (3)

    «Неграмотный» или «не грамотный»: слитно или раздельно?

    Если коротко, то пишется слитно, когда утверждается безграмотность, и пишется раздельно, когда отрицается грамотность.

    Он неграмотный. (Утверждается безграмотность).

    Он не грамотный. (Отрицается грамотность).

    (Этот принцип действует и для наречия «неграмотно»).

    Reply ↓
  5. PerlAmutor

    Спасибо. Довольно интересные трюки.

    Reply ↓
  6. BenGunn

    (3) Да ну, нафиг! Посмотрел твой профиль… Да ты, оказывается, флудер! Сказать только ради того, чтобы сказать?! Отличная позиция! А не хочешь сделать что-нибудь полезное? Ну, кроме того, что раздувать щеки с умным видом?!

    Reply ↓
  7. BenGunn

    (6) Спасибо!

    Reply ↓
  8. jONES1979

    (7) Зачем переходить на личности, вам скучно? За полезное на работе деньги платят, а не звёздочки в интернете. Форум — это по определению место для общения, что позволяет отвлечься. Кого первого-то на флудеразм пробило? Поправили бы свою опечатку и копали дальше,.. а не капали.

    За статью спасибо, кстати. С моей помощью теперь она чуть ли не идеальна))

    Reply ↓
  9. BenGunn

    (9)

    Ну я говорю, флудер!

    Кстати, где ты здесь видишь форум? Здесь специалисты делятся знаниями, а не ищут орфографические ошибки. Теми самыми знаниями, кстати, которые кто-нибудь использует в той самой работе, за которую деньги платят. А судя по тому, что пишешь в коментах, тебе еще очень далеко до такого уровня… Поищи развлекуху где-нибудь на Фейсбуке, там таких как ты любят

    Reply ↓
  10. jONES1979

    (10)

    — К чему эти ярлыки? Не опускайтесь до моего уровня!

    — Форум написано вверху.

    — Я не искал ошибок, они сами бросаются в глаза и сбивают восприятие.

    — За знания я никогда не устану говорить спасибо! Спасибо!

    Reply ↓
  11. Oldsad

    отличная статья

    Reply ↓
  12. fomix

    1. Изменились параметры процедуры «НачатьПомещениеФайлов», поэтому код процедуры «ПриОткрытии» будет таким (по крайней мере для 1С:Предприятие 8.3 (8.3.12.1685), БП 3.0):

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

    Показать

    2. Выполнения скрипта из COMОбъект(«WScript.Shell») требует особых прав и без подтверждения такого действия на сервере не работает! Соответственно, ваша обработка не отрабатывает и каждый раз вываливается запрос на подтверждение((( Можно просто поставить вместо этого цикл.

    Reply ↓
  13. BenGunn

    (13) Уточни, пожалуйста, что имелось в виду по п.2

    Reply ↓
  14. BenGunn

    (13) По п.1, тестировалось на 8.3.13.1513. Что на более ранних релизах, сказать не могу. На поздних работает

    Reply ↓
  15. fomix

    (15) Платформа тут не при чем! В последнем релизе БП 3.0 (и скорее всего и в других конфигурациях тоже!) изменился вызов команды «НачатьПомещениеФайлов»

    Reply ↓
  16. fomix

    (14) При попытке выполнить скрипт, 1с-ка стандартно спрашивает «…пытается выполнить вызов команды WScript.Shell. Подтверждаете? Да/Нет». Отвечаешь Да и по-новой вываливается этот диалог и так до посинения. Ну тебе это нужно было для «тормоза», поэтому в реальной жизни вряд ли кому-то пригодится. Так что, не заморачивайся!

    Reply ↓
  17. BenGunn

    (17) Точно! Фоновое задание при таком подходе запускается от имени DefUser, соответственно, COM объекты создаются только в безопасном профиле…. Ёкрныйбабай! Сам на этом споткнулся! Есть предложения по решению вопроса? (Ну, кроме того, что включать процедуру фонового задания в конфу)?

    Reply ↓
  18. BenGunn

    (16) Ничё не понял… При чем тут вообще БП?

    Глобальный контекст (Global context)

    НачатьПомещениеФайлов (BeginPuttingFiles)

    Синтаксис:

    НачатьПомещениеФайлов(<ОписаниеОповещенияОЗавершении>, <ПомещаемыеФайлы>, <Интерактивно>, <УникальныйИдентификаторФормы>, <ОписаниеОповещенияПередНачаломПомещенияФайлов>)

    Reply ↓
  19. fomix

    (19) Насчет БП точно — я не прав! Платформа 8.3.15.1700:

    Все верно про синтаксис:

    НачатьПомещениеФайлов(<ОписаниеОповещенияОЗавершении>, <ПомещаемыеФайлы>, <Интерактивно>, <УникальныйИдентификаторФормы>, <ОписаниеОповещенияПередНачаломПомещенияФайлов>)

    Но у вас параметр: <ПомещаемыеФайлы> = РеквизитФормыВЗначение(«Объект»).ИспользуемоеИмяФайла (тип строка). Так не работает!

    А вот как я написал:

    ОписаниеФайлаВО = Новый ОписаниеПередаваемогоФайла(ИмяФайлаОбработки());
    ПомещаемыеФайлы = Новый Массив;
    ПомещаемыеФайлы.Добавить(ОписаниеФайлаВО)

    работает..

    Reply ↓

Leave a Comment

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