Имя: Пароль:
1C
1С v8
Как организовать очередь фоновых заданий?
0 ssalikoff
 
06.04.22
07:44
При наступлении некоего события нужно запустить фоновую обработку на сервере.
Однако, если событие снова произойдёт до окончания работы фоновой обработки, то нельзя запускать её второй экземпляр, а поставить в очередь и запустить только после окончания работы текущего экземпляра обработки.

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

Как это сделать?
1 xkanix
 
06.04.22
07:49
Посмотреть как сделана очередь заданий во фреше (в любой типовой которая есть во фреше).
2 ssalikoff
 
06.04.22
07:51
(1) А можно поточнее указать куда смотреть? Допустим, пусть для примера это будет БП 3.0. Где там очередь заданий?
3 xkanix
 
06.04.22
07:59
(2) Подсистема АдминистрированиеСервиса -> ОчередьЗаданий
4 xkanix
 
06.04.22
08:02
В исправление к (3) - основное в ТехнологияСервиса -> ОчередьЗаданий (то что раньше написал это UI подсистема, в ней совсем не всё).
5 ssalikoff
 
06.04.22
08:13
(4) Посмотрел. Хрень какая-то. В общих модулях ОчередьЗаданий*  одни функции-заглушки. Никакого реального кода.
Можно объяснить, в чём суть методики?
6 rozer76
 
06.04.22
08:20
А проще почему нельзя? РЗ с минимальным интервалом обрабатывает очередь
7 ssalikoff
 
06.04.22
08:24
(6) не понял, что вы хотели сказать. Можно ещё раз, для не самых сообразительных?
8 Serg_1960
 
06.04.22
08:30
ТелепатБот :) Вам предложили создать регламентное задание, которое будет обслуживать очередь экземпляров фонового задания.
9 rozer76
 
06.04.22
08:31
(7) событие - в очередь, РЗ разбирает ее с минимальным интервалом
10 xkanix
 
06.04.22
08:36
(5) Да, действительно.
Видимо решили выпилить код от БТС, а на фреше его как-то добавляют (через расширение, например - так, конечно, и обновлять) проще.
Ну тогда - прошу прощения. Без "Библиотека технологии сервиса" видимо смотреть реализацию негде.
11 ssalikoff
 
06.04.22
08:39
(9) Идею понял. Хотя как-то это не очень красиво.
Некрасиво, что приходится что-то писать в базу данных, а потом оттуда постоянно читать.
Хотелось бы что-нибудь поизящнее.
12 lEvGl
 
гуру
06.04.22
08:48
если задание имеет склонность не успевать отрабатывать до следующего запуска, то есть теоретическая вероятность "бесконечного цикла", когда ожидающие задания будут накапливаться, как следствие - сервер в ужасе. это произойдет из за Обязательного запуска следующего по расписанию задания. этого можно избежать, если пропускать те запуски, которые должны были произойти в момент уже работающего предыдущего задания, не запускать их принудительно. ну а чтобы определить работает сейчас какое то задание или нет, хранить признак запущенного задания все равно где то придется. храните в файле, если в базе не хотите :)
13 ssalikoff
 
06.04.22
08:59
(12) Хотелось бы хранить это в оперативной памяти сервера. Или как-то оповещать работающее задание, чтобы оно перезапустилось после завершения. Но, по-видимому, в рамках архитектуры 1С это невозможно. Буду делать, как мне посоветовали выше
14 Serg_1960
 
06.04.22
09:16
Ох и любите вы всё усложнять :)

Фоновое задание (например, "ОчередьЗаданий"), реализующее очередь из запущенных экземпляров фонового задания, общается с ними, например, через механизм сообщений. При начале работы очередной экземпляр сообщает ОчередьЗаданий чтобы его включили в очередь и ждёт разрешения на продолжение исполнения от ОчередьЗаданий; получив разрешение, продолжает работу и сообщает о своём завершении в ОчередьЗаданий. ОчередьЗаданий обрабатывает сообщения от экземпляров, "двигает" очередь, разрешает работать первому в очереди; автоматически завершает свою работу при исчезновении очереди. Очередной экземпляр, перед началом работы, проверяет наличие ОчередьЗаданий и запускает её при необходимости. Виртуальная очередь может быть реализована в виде хранения в памяти (можно в хранилище) любой структуры (например, массив)... Как то вот так :)
15 ssalikoff
 
06.04.22
12:33
(14) вот это непонятно: «общается с ними, например, через механизм сообщений». Как можно что-то сообщить фоновому заданию, и как можно организовать бесконечный цикл ожидания внутри фонового задания?
16 Serg_1960
 
07.04.22
09:11
(15) Для общения между фоновыми заданиями, например, можно использовать СообщениеПользователю() и ПолучитьСообщенияПользователю(). Только не надо забывать их удалять перед завершением работы фонового задания. Иначе юзверь будет чиать их чат :)

Для реализации простой очереди ожидания завершения работы предыдущего экземпляра, можно использовать ПолучитьФоновыеЗадания() с отбором по ИмяМетода и Состояние. Найти последний запущенный экземпляр и через ОжидатьЗавершение() - поставить на паузу текущий экземпляр.
Не совсем в тему, есть ветка с обсуждением нечто подобного - Завершение фонового задания
17 ProgAL
 
07.04.22
10:47
Фоновые = ФоновыеЗадания.ПолучитьФоновыеЗадания();
    
    Для Каждого Фоновое из Фоновые Цикл
        
        Если Найти(Фоновое.Ключ, "имя вашего задания, которое можно посмотреть в консоли заданий") > 0 И Фоновое.Состояние = СостояниеФоновогоЗадания.Активно Тогда
            
            Предупреждение("Фоновое задание еще выполняется.");
                        
            Возврат;
            
        КонецЕсли;    
        
    КонецЦикла;
18 rudnitskij
 
07.04.22
16:55
(17) на сервере "Предупреждение"? Оригинально
19 ProgAL
 
07.04.22
18:56
Это был клиентский код.
20 ДедМорроз
 
07.04.22
22:15
А зачем запускать еще раз?
Просто пишем то,что нужно в регистр,а задание перед завершением проверяет,а не нужно ли чего ещн сделать.
Если задания нет,то запустить новое.
Очередь нужна там,где есть не одно задание,а пул.
21 Serg_1960
 
08.04.22
09:22
(20) Если не забывать о многопользовательском режиме работы и связанной с этим асинхронности событий, то может возникнуть ситуация, при которой в момент завершения задания произойдёт запись в регистр. Первый процесс завершает работу задания, второй - не вызывает новое так, как старое ещё не завершилось.
22 ДедМорроз
 
09.04.22
15:41
А блокировки вамина что?
Задание перед завершением также ставит блокировку на регистр,читает,а не нужно ли что сделать,и если не нужно сообщает,что закончено.
После этого,любой желающий перед запистю задания в оегистр также ставит блокировку,и,если записано,что задания нет,то пишет,что он создал новое и запускает его.
Тогда два сразу не запустятся.
23 ssalikoff
 
09.04.22
22:44
(16) А я и не знал, что СообщениеПользователю() работает на сервере. Теперь знаю.
24 ДедМорроз
 
09.04.22
23:00
(23) оно и в фоновом задании работает и потом их даже можно получить.
По крайней мере,всю нотификацию о работе фоновых заданий очень успешно через сообщения делать.
25 ssalikoff
 
09.04.22
23:43
(24) А вот получит ли фоновое задание сообщение через ПолучитьСообщенияПользователю() от другого фонового задания, запущенное в другом сеансе?  В справке явно об этом не сказано. Вообще, идеологически, кажется, что доступ к чужим сообщениям не должен предоставляться.
26 Serg_1960
 
09.04.22
23:51
(22) Sorry, имхо, Обращение к базе; организация режима ожидания установки/снятия блокировки; чтение/запись... использование регистра, в данном конкретном случае, имхо, не эффективно и не оптимально.
27 ДедМорроз
 
10.04.22
00:18
(25)получит прекрасно.
Я даже для передачи команд использовал отдельное фоновое задание,чьи сообщения читали целевые.
Там единственная проблемамв том,что без удаления они очень быстро накапливаются,а с удалением - не все их получают.

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

Есть еще вариант с "хвостом".
Когда задание выходит на состояние "нечего делать",то оно ставит в регистр это состояние и дату его установки и ждет в течение какого-то времени,проверяч,что новых заданий не появилось,а когда процесс ставит задание и видмт предыдущее в состоянии ожидания,он использует блокировку,чтобы исключить уход задания из жизни в момент постановки новой задачи.
28 ssalikoff
 
10.04.22
12:57
(27) Спасибо за науку. Возьму на вооружение этот метод. Жаль, что это на уровне платформы не поддерживается, приходится пользоваться подобными «костылями»
29 vi0
 
10.04.22
13:12
(0) а для чего эта очередь, и какой длины она допустима?
что за задача решается?
30 ssalikoff
 
11.04.22
01:00
(29) Когда на склад поступает товар, срабатывает триггер и образовавшиеся свободные остатки начинают распределяться согласно заранее заданным правилам по заказам клиентов, по разным резервам для отделов. Это распределение может работать несколько минут, и если в это время произойдет другое поступление, то схема «ломается», если позволить запустить параллельное задание по распределению. Нужно чтобы распределения работали монопольно, строго последовательно
31 vi0
 
11.04.22
03:19
(30) а для чего именно очередь? в триггере хранится какая то уникальная для события информация, или только сам факт что событие произошло?
почему нельзя, чтобы триггер писал куда-то инфу о факте события, а одно рег задание, например, раз в минуту например опрашивало бы наличие и обрабатывало бы его?
32 ssalikoff
 
11.04.22
03:40
(31) да, в триггере есть специфическая информация, передаваемая в качестве параметра фоновому заданию
33 vi0
 
11.04.22
03:50
(32) и пиши ее в регистр сведений, организуй очередь там
почему ты не хочешь бд использовать? а если сервер зависнет и перегружать надо будет? откуда будешь восстаналивать инфу от тригеров?
я смотрю в (6) тебе уже советовали подобное
34 ssalikoff
 
11.04.22
03:52
(33) Потому что писать что-то в базу данных и потом регулярно оттуда считывать — это плохая, некрасивая идея. В (16) мне посоветовали куда более красивое решение, которым я и воспользовался.
35 rphosts
 
11.04.22
03:55
(0) сделай регулярно запускаемый (например раз в 3 сек) процесс который будет диспетчеризировать очередь фоновых.
36 ssalikoff
 
11.04.22
03:57
(35) Каждые три секунды запускать процесс — кажется мне плохим советом. Выше было предложено красивое решение через ПолучитьСообщенияПользователю() и ОжидатьЗавершение()
37 rphosts
 
11.04.22
04:11
(36) >Фоновое задание (например, "ОчередьЗаданий"), реализующее очередь из запущенных экземпляров фонового задания,
непрерывно выполняемое? Оно загрузит на около 100% 1 ядро процессора сервера. Имхо, про красоту вам только кажется: процесс занявший одно ядро и процесс регулярно получающий управление и если нет в нём нужды возвращающий управление серверу.

>Выше было предложено красивое решение через ПолучитьСообщенияПользователю() и ОжидатьЗавершение()
Это только инструмент, также можно в РС писать, можно в Справочник - у каждого из вариантов есть свои плюсы и минусы.
38 vi0
 
11.04.22
04:25
(34) "Потому что писать что-то в базу данных и потом регулярно оттуда считывать — это плохая, некрасивая идея"
откуда такие мысли?
39 vi0
 
11.04.22
04:27
(38) + всё решают цели задачи, требования, имеющиеся ресурсы
считывать раз в минуту одну запись регистра, это такой мизер
40 vi0
 
11.04.22
04:35
подобным образом через регистр работает движок многопоточки от Евгения Павлюка
https://habr.com/ru/post/255387/
https://github.com/wizi4d/TaskManagerFor1C