gifts2017

Как исключить запуск обработки несколькими пользователями одновременно

Опубликовал Илья Васильев (swimdog) в раздел Программирование - Практика программирования

Иногда возникают ситуации, когда несколько пользователей одновременно используют обработку, которая создает объекты в базе. Например, производят выгрузку в другие базы через непосредственное подключение. Или с помощью обработки создают новые документы. В результате, возникает нежелательное дублирование. Как этого можно избежать?

Решение простое, но не всегда очевидное. В обработке создается реквизит Блокировка, тип Справочник.Номенклатура. При желании можно выбрать любой другой справочник. В версии 8.2 для блокировки справочника даже не нужны права на изменение.

 

В выбранном справочнике создается предопределенный элемент. В примере он называется "ЭлементДляБлокировкиОбработки". Наличие предопределенного элемента позволяет использовать блокируемый объект во всех узлах распределенной базы, а также гарантирует его сохранность от удаления.

Если база не распределенная или нет желания/возможности добавлять предопределенный элемент, то для блокировки можно использовать любой объект, введенный пользователем системы. Или добавить свой элемент. В этом случае первая строка кода будет выглядеть как Справочники.Номенклатура.НайтиПоКоду("1") или Справочники.Номенклатура.НайтиПоНаименованию("ЭлементДляБлокировкиОбработки") или запросом и получить объект.

 

В обработке, в процедуре "Перед открытием" пишем такой код:

 

Блокировка = Справочники.Номенклатура.ЭлементДляБлокировкиОбработки.ПолучитьОбъект();
Попытка
   Блокировка.Заблокировать();
Исключение
   Сообщить("Обработка уже используется!");
КонецПопытки;

 

В исключении надо прописать все необходимые действия, исключить нежелательные действия. Например, закрыть обработку. Или заблокировать кнопки по созданию объектов.

Если надо увидеть кто заблокировал, то есть, кто уже пользуется обработкой, то выполняем блокировку без конструкции Попытка-Исключение. И средствами платформы получаем максимально подробную информацию, начиная с имени пользователя и заканчивая номером сеанса. 

 

P.S. Для УФ можно использовать метод ЗаблокироватьДанныеДляРедактирования

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Андрей Суровов (Andris_infostart) 17.09.14 10:32
А почему бы не сделать проверку на наличие дублирования перед записью нового объекта?
2. Илья Васильев (swimdog) 17.09.14 10:55
(1) Andris_infostart, конечно, можно сделать проверку
3. Илья Коротков (molodoi1sneg) 17.09.14 10:58
Решение интересное, возьму на заметку.
4. Val Yan (valvit) 17.09.14 09:33
5. ediks (ediks) 17.09.14 14:44
(1) Насколько я понимаю, задача ставилась не допустить параллельного запуска этой обработки.
Определить же в процессе работы обработки, что создается дублирующий объект или "так и должно быть" в общем случае затруднительно. Да к тому же требует дополнительных усилий :)
6. Семён Павлюков (7OH) 17.09.14 16:01
Попытка Исключение ?
Может лучше
Если Блокировка.Заблокирован() Тогда
//сообщить и\или возврат;
КонецЕсли;

?
7. Илья Васильев (swimdog) 17.09.14 15:07
(6) 7OH, У меня такой вариант не взлетел. Я его пробовал.
8. Яков Коган (Yashazz) 17.09.14 15:51
Вот кстати чего мне не хватает. так это "второй стороны" к объекту Блокировка. Нечто вроде расширенного Заблокирован(), чтобы возвращало, кем, когда и откуда.
9. Arkadiy Ezhov (ezhikofff) 17.09.14 15:57
можно добавить константу типа булево, и проверять ее перед запуском механизма обработки:)
10. Илья Васильев (swimdog) 17.09.14 16:33
(9) ezhikofff, работа через константу подразумевает ручную корректировку при аварийном завершении работы программы с работающей обработкой. Мое решение работает полностью автоматически.
11. Arkadiy Ezhov (ezhikofff) 17.09.14 17:01
(10) swimdog, я не настаиваю, просто предложил.
12. Андрей Суровов (Andris_infostart) 17.09.14 19:33
(5) ediks, вариант про блокировку для повторного запуски обработки хорош, но вопрос в топике был следующим:
"В результате, возникает нежелательное дублирование. Как этого можно избежать?" ©
Поэтому проверка на дубли, по моему мнению, будет уместнее (в контексте поставленного вопроса), даже если запустят в 2 и более раз эту обработку.

По теме получается, что вопрос задан"как избежать дублирования?", а по факту приведён пример того, как запретить повторный запуск обработки, которая может наделать дублей.
13. Борис Скворцов (gaglo) 18.09.14 09:38
(10) Можно добиться некого полуавтомата, если употребить не константу, а запись некого регистра, при запуске обработки создавать, на выходе удалять, записывать дату (и время) начала блокировки и на старте проверять не просто наличие такой записи, но и дату - скажем, считать вчерашнюю запись уже неактуальной. Для обработок, которые достаточно редко запускаются, должно хватить. (8) Кстати, в регистре можно записать и кто, и откуда, и даже зачем.
14. Andrey Smirnov (dusha0020) 18.09.14 10:24
(13) gaglo,
если употребить не константу, а запись некого регистра
А я бы не стал без нужды плодить сущности. Есть простая проблема и автор предложил простое решение. Если проблема сложнее то и решение нужно более сложное.
(7) swimdog, Это странно. Попытка -> Исключение это как-то не очень кошерно. Но все равно спасибо за идею.
15. Макас (makas) 18.09.14 10:44
Иногда возникают ситуации, когда несколько пользователей одновременно используют обработку, которая создает объекты в базе. Например, производят выгрузку в другие базы через непосредственное подключение. Или с помощью обработки создают новые документы. В результате, возникает нежелательное дублирование.



У моих бухов такое возникает не иногда, а каждый день. Почти :)
16. ediks (ediks) 18.09.14 10:58
(6) Собственно в помощи все описано. Выделил жирным шрифтом ключевое предложение.
Синтаксис:

Заблокирован()
Возвращаемое значение:

Тип: Булево.
Истина - элемент заблокирован; Ложь - в противном случае.
Описание:

Определяет, заблокирован ли элемент данным объектом.

Доступность:

Сервер, толстый клиент, внешнее соединение.
Примечание:

Следует учитывать, что этот метод используется для проверки блокировки объекта базы данных конкретным объектом встроенного языка. Он не может быть использован для проверки, заблокирован ли вообще объект базы данных, например, другими пользователями.
Stim213; kosten; swimdog; +3 Ответить
17. Илья Васильев (swimdog) 18.09.14 10:59
(11) ezhikofff, константа это первый приходящий на ум вариант :) Я ответил, чтобы показать возможные проблемы данного пути
18. Илья Васильев (swimdog) 18.09.14 11:10
(12) Andris_infostart, согласен, что проверка дублей хороший вариант. Надо смотреть каждый случай. В моем случае проверка приведет к дополнительным одиночным запросам.А с помощью запрета на одновременный запуск обработки я полностью исключу вероятность ошибки.
19. Владислав Петров (Владbckfd) 20.09.14 17:05
Уточните, пож-ста, как вызвать обработку "перед открытием"
20. ediks (ediks) 21.09.14 17:36
(19) Эта блокировка вызывается непосредственно в форме обработки в событии формы "ПередОткрытием".
21. IMalyshev (allegrosoft) 22.09.14 18:09
И сколько по времени держится блокировка? Если не ошибаюсь, есть ограничение по времени и оно не большое.
22. Виталий Жуланов (VZhulanov) 22.09.14 21:10
Лучше создайте отдельный справочник Блокировки (Наименование, КтоЗаблокировал, КогдаЗаблокировал)
В менеджере справочника надо вставить функцию ЗаблокироватьДействие(Название)
Эта функция возвращает Пустой элемент справочника в случае успешной блокировки или возвращает ссылку на элемент справочника при неудаче.
Из этой ссылки можно будет получить инфу Кто и Когда заблокировал это действие.
И еще одну фунцию Разблокировать(Название)
В функции передается название действия, которое надо заблокировать.

Такая реализация позволит реализовать механизм блокировок для неограниченного числа действий/обработок,
а также не придется создавать левых элементов в других справочниках, что ну крайне неверно и некрасиво.
23. Илья Васильев (swimdog) 22.09.14 23:02
(22) VZhulanov, если блокировать надо много чего, то можно и справочник создать. Если обработка одна, то зачем так заморачиваться?
24. Maxim Kolkin (the1) 23.09.14 08:47
Не проще использовать существующие объекты конфигурации? Например в типовых есть или справочник, или регистр "Сохраненные настройки". Туда, на мой взгляд, и следует записывать "блокировочную" запись. Это помимо очевидного "ЗначениеВФайл". А корежить типовые - увольте
25. Илья Васильев (swimdog) 23.09.14 09:57
(24) the1,
1. А причем здесь "ЗначениеВФайл"?
2. В конфигуратор можно вообще не лезть. Блокировать можно любой объект. Предопределенные значения нужны в основном для распределенных конфигураций. А в локальной базе блокировать можно любой понравившийся объект.
26. Maxim Kolkin (the1) 23.09.14 10:45
(25) автор предлагает создать предопределенный элемент справочника. Научите делать это без конфигуратора?
27. Maxim Kolkin (the1) 23.09.14 10:50
(25)
При нажатии на кнопку "Создать документы"

ОбработкаВыполняется = ЗначениеИзФайла(<ИмяФайла>);
Если ОбработкаВыполняется Тогда Предупреждение("Блокировка!"); Возврат КонецЕсли;


ОбработкаВыполняется = истина;
ЗначениеВФайл(<ИмяФайла>, ОбработкаВыполняется);

....

ОбработкаВыполняется = ложь;
ЗначениеВФайл(<ИмяФайла>, ОбработкаВыполняется);
...Показать Скрыть
28. Виталий Жуланов (VZhulanov) 23.09.14 11:04
В 1С 7.7. я для таких целей просто использовал внешний файл.
Тоже не надо лезть в конфигурацию или блокировать существующие объекты.

Чтобы заблокировать создавал и открывал файл.
Чтобы разблокировать - удалял файл.
Если файл не удаляется, значит обработка запущена другим юзером.
29. Виталий Жуланов (VZhulanov) 23.09.14 11:06
(27)
а если зависнет чего, то в файла так и останется Истина

Блокировка хороша тем, что снимется автоматом
30. Илья Васильев (swimdog) 23.09.14 11:23
(26) the1, добавил ответ в текст статьи
31. Илья Васильев (swimdog) 23.09.14 11:24
(21) allegrosoft, У меня блокировка держалась больше часа. Дольше не проверял, но явных ограничений в документации 1С не видел.
32. Епрст (Ёпрст) 23.09.14 11:38
Хорошее решение, почти полный аналог с клюшечным вариантом отлова активных пользователей.
Все идеи с клюшек в снеговик кочуют помаленьку.. реинкарнация в новом виде.
:)
33. ediks (ediks) 23.09.14 11:40
(26) В 8.3.3 Для объектов конфигурации, которые могут содержать предопределенные данные, реализовано свойство ИмяПредопределенныхДанных. Заполнив это свойство у существующего объекта (или у вновь созданного) Вы получите предопределенный элемент, созданный без конфигуратора.
34. Вадим Никонов (V.Nikonov) 24.09.14 14:18
Блокировки одновременного запуска нескольких экземпляров обработки возникают не только при загрузке данных. Есть множество регламентных процедур (в частности, проведение по партиям), множественный запуск которых может приводить к взаимным блокировкам...
В этом смысле создание справочника "Блокировки" хорошая идея. В справочнике создают запись под каждую Монополизируемую обработку и постоянно обновлять отметку о срабатывании "МонопольнойОбработки". Ведь, простая блокировка не является панацеей от зависания... В случае, если сеанс организовавший блокировку зависнет, то блокировка будет оставаться, а основной сеанс обработки не работать!
Соответственно, есть смысл при старте не только проверять Факт блокировки, но и анализировать кем и когда заблокировано, а в случае обновления отметки о срабатывании МонопольнойОбработки, можно диагностировать критические зависания первичного сеанса... Соответственно можно вычислить зависшие сеансы и призвать Администратора для решения проблем.
35. haz haz (hazd) 05.10.14 21:00
36. haz haz (hazd) 12.10.14 00:58
согласен с Andris_infostart, проверять перед записью и нет проблем.
37. Роман Антонов (ronhard) 20.10.14 16:06
А надо ли разблокировать выбранный элемент при закрытии обработки, или блокировка при закрытии снимется автоматом?
38. Илья Васильев (swimdog) 20.10.14 22:42
(37) ronhard, Блокировка снимется автоматом
39. Павел Колмаков (Stim213) 07.11.14 12:44
Имхо, решение не совсем верное.

Справочник Номенклатура или любой другой - не предназначены для подобной операции. Это неверное архитектурное решение. Если с вашими базами будут работать другие программисты, они не поймут назначение этого костыля и запросто его удалят.
Кроме того, использовать предопрделенные элементы в типовых объектах это уж точно не верно. Вы предлагаете универсальное решение, а оно в таком случае должно учитывать все способы поддержки. Наверное, глупо будет снимать конфу с полной поддержки, включать возможность изменения типового справочника ради одновременной работы одной единственной внешней обработки.
Без острой необходимости лучше не менять типовые объекты!
Хочется чего-то нового - добавляйте новые объекты в новых подсистемах.

Находить по коду/наименованию тоже не совсем верно. Код и наименования объектов могут измениться, элементы могут быть так же удалены.

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


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

А лучше вообще использовать Журнал регистрации, записывать в него время выполнения, результат. И при открытии обработки анализировать и выводить эти записи пользователю, чтобы он видел, что, к примеру, выгрузка была проведена Ивановым 10 секунд назад с положительным результатом.
40. Илья Васильев (swimdog) 07.11.14 13:13
(39) Stim213, ключевое слово "одновременно". Журнал регистрации для этого не нужен.
41. Алексей (kaging) 04.12.14 15:41
(13) gaglo, конечно правильнее использовать регистр сведении, к примеру с одним измерением "имя обработки", при запуске делать запись в регистр, а при закрытии обработки вычищать его. Ну а на случай аварийного завершения программы надо бы при первом запуске программы тоже его чистить.
42. Максим Безруков (bzmax) 04.12.14 17:49
Проверка использования обработки без изменений конфигурации.
(Для последних версий конфигураций основанных на БСП.)
(за исключением кода самой обработки)

1) Включаем в "Общих настройках" флаг "Дополнительные реквизиты и сведения"
2) Заходим в пункт "Дополнительные сведения"
см.рис. Начало_настроек_блокировки.png

3) Добавляем для "Пользователя" новые дополнительные сведения с типом значения булево.
см.рис. Доп_свойство_блокировка.png
см.рис. Список_доп_свойств_блокировок.png

Теперь в нашем распоряжении типовой регистр сведений "ДополнительныеСведения"
и элементы типового Плана вида харакетристик "ДополнительныеРеквизитыИСведения"
(в данном случае Блокировка обработки №1 и Блокировка обработки №2)

В регистр сведений "ДополнительныеСведения" мы независимо можем записывать записи по полям:
Объект - Пользователь
Свойство - Элемент плана вида характеристик.
Значение - Булево

см.рис. Рег_ДополнительныеСведения.png

4) Осталось только нужную нам обработку "научить" (дописать код)
работать с типовым регистром сведений "ДополнительныеСведения"
На предмет анализа и формирование соответствующих записей.
И программно в коде обработки назначить ей соответствующий элемент плана видов характеристик.
(Код писать не буду. и так все "разжевал" :))

ИТОГ:
Получаем подобный механизм контроля, с минимальными изменениями типовых механизмов и объектов метаданных.
И можем не только мониторить на предмет блокировки, но и смотреть кто и какую обработку использует в текущий момент.
Прикрепленные файлы:
43. Разве это имеет значение (-fox-) 05.12.14 18:00
А почему нельзя воспользоваться механизмом управляемых блокировок?
44. Илья Васильев (swimdog) 05.12.14 22:31
(43) -fox-, блокировок чего? объектов? Так они могут блокироваться как угодно, в том числе с помощью управляемых блокировок. При запуске двух загрузок или двух потоков создания документов может не происходить пересечений на конкретном объекте.
45. Илья Васильев (swimdog) 05.12.14 22:33
Для всех, кого интересует получение блокирующего пользователя, я дополнил статью. Все делается одной строкой кода, без создания регистров сведений :)
46. Илья Васильев (swimdog) 05.12.14 22:39
Вообще, в данной статье я предложил конкретное решение конкретной, очень узкой задачи. При рассмотрении похожих задач, но с другими начальными условиями, возможно использование других решений. Они не лучше и не хуже. Все зависит от деталей. В моем случае, это решение было наименее трудозатратным в создании и поддержке. И я не вижу смысла обсуждать в комментариях альтернативные варианты, которые можно использовать в похожих задачах.
Пишите статьи о своих вариантах, приводите ссылки и будьте счастливы :)
ediks; bzmax; +2 Ответить
47. Разве это имеет значение (-fox-) 08.12.14 09:55
(44) swimdog,
Создается спр. (Если будет несколько обработок) или константа и их блокируешь.

На сколько я понял, у тебя тоже самое, но использован спр. "Номенклатура" и специально для этого созданный элемент "ЭлементДляБлокировкиОбработки".
ИМХО лучше не засорять спр. заведомо не используемой информацией.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа