Обработчик "После завершения транзакции" своими руками

Публикация № 1243723

Разработка - Практика программирования

Быстрые сообщения событийная модель commit

Обработчик "Сразу после завершения транзакции" очень востребован в механизме обмена мгновенными сообщениями, развитием которого фирма 1С заинтересовались настолько, что уже создала "Сервисы интеграции". Но платформа 8.3.17 всё еще не имеет полноценного обработчика "После записи" в подписках на события.
Обработчики событий ПослеЗаписи и ПослеЗаписиНаСервере реализованы только в форме клиентского приложения. Событие завершения транзакции легко отлавливается журналом регистрации, технологическим журналом и механизмом версионирования. Что мешает разработчикам платформы поместить этот механизм в подписки - загадка!

Такой обработчик помог бы в решении как минимум двух задач:
  1. Мгновенная отправка сообщений во внешние базы, интеграционные шины, брокеры сообщений
  2. Быстрая постобработка проведенных документов - формирование бухгалтерских проводок, различных трансляций в управленческий учет или МСФО
Да, эти механизмы можно реализовать и на регламентных заданиях. Цикл запуска РЗ можно выставить хоть в 5 секунд, и это будет работать. Но это как-то не спортивно:
  1. Лог РЗ засоряется холостыми пусками
  2. Сервер находится постоянно под нагрузкой, даже ночью (а вдруг бухгалтеру не спится!)
  3. Эффект 100%-ной загрузки процессора, когда в базе нет ни одного пользователя и происходит частый запуск регламентного задания (см. //appaas.u-clouds.com/public/996126/)
 
Кроме того, уверен, есть бизнесы, для которых и 5 секунд непростительная задержка при передаче данных. В общем, обработчик "после завершения транзакции" явно востребован, надо искать решение!
 
Честно признаюсь, то что описано далее, работает на низко нагруженной базе (в пике до 200 пользователей, в среднем проводится 1-2 документа в секунду). Поэтому было бы интересно подружиться со смельчаком, который готов опробовать эту идею в более интенсивной среде.
 
Итак, сама идея:

У объекта Блокиро вкаДаных есть замечательное свойство - останавливать выполнение кода, пока не завершится транзакция в другом процессе, или пока не закончится время ожидания блокировки (по умолчанию это время равно 20 секундам). А что если использовать это свойство как пусковой механизм для старта постобработки сразу после завершения транзакции?
 
Проиллюстрирую идею на двух конкретных задачах:

Задача №1. Требуется запускать постобработку трансляции регистра бухгалтерии Хозрасчетный в управленческую подсистему сразу после событий:
  • Проведение/перепроведение документов
  • Снятие с проведения документов
  • Ручная корректировка проводок
Задача №2. Требуется запускать выгрузку во внешнюю систему сразу после записи определенных справочников и документов. Внешняя система способна обрабатывать многопоточную загрузку, единственное ограничение - нельзя параллельно загружать объект с одним идентификатором.
 
Для обеих задач должно выполняться важное условие - пользователи не должны почувствовать замедления в работе.
 
Для Задачи №1:
  • Создадим общий модуль Трансляция_БУ_УУ
  • Создадим подписку на событие ПриЗаписиРегБух, где источник РегистрБухгалтерииНаборЗаписей.Хозрасчетный и событие: ПриЗаписи.
  • Создадим регистр сведений ОчередьТяжелыхДокументов, измерения: Док, Миллисекунды
  • Создадим регламентное задание ОбработкаОчередиТяжелыхДокументов
 
Для Задачи №2:
  • Создадим общий модуль ОбменСВнешнейСистемой
  • Создадим подписку на событие ПриЗаписиДокСпр, где источниками являются справочники и документы, участвующие в выгрузке, событие: ПриЗаписи.
  • Создадим регистр сведений ОчередьТяжелыхДокументов2, измерения: ДокСпр, Миллисекунды
  • Создадим регламентное задание ОбработкаОчередиТяжелыхДокументов2
Далее описывается алгоритм, идентичный для обеих задач. Фразу "набор записей" можно заменить на "ссылочный объект", нюансы кода показаны в конце статьи.

В процедуре обработчика подписки установим управляемую блокировку по регистратору на набор записей регистра. Такая блокировка никому не будет мешать, кроме фонового задания, которое мы запустим следом. Подписка будет вызываться и при снятии с проведения документа, что так же важно для обнуления трансляции в УУ. Подписка будет вызываться дважды при проведении, если у документа стоит признак "Удалять движения автоматически", так конечно уже давно никто не делает, но надеюсь сервер 1С раздаёт разрешения на блокировки согласно очерёдности начала попыток блокировки, у меня проверить возможности не было.
 
В фоновое задание передадим ссылку Регистратора и Хеш-сумму содержимого набора записей регистра – будем считать её идентификатором версии. Для Задачи №2 тоже будем передавать хеш содержимого документа, т.к. атрибут Версия меняется только после завершения транзакции.
 
В процедуре фонового задания откроем программную транзакцию и в цикле будем пытаться установить блокировку на регистр по переданному регистратору. Количество циклов надо подобрать эмпирически исходя из самых плохих прогнозов времени проведения самого тяжёлого документа. Я выбрал 10 циклов, это 10 минут, исходя из 60 секунд времени ожидания блокировки данных, которое определил админ базы.
 
Блокировка выполняется в попытке, но ошибка типа «в этой транзакции уже происходили ошибки» исключена, так как внутри попытки нет вложенных транзакций.
 
Если блокировка преодолена, значит транзакция по записи набора в клиентском процессе завершилась. В этот момент пользователь побежал дальше, для него ожидание закончилось. Мы передали обработку результата завершенной транзакции в фоновое задание. В фоновом задании можно было и не открывать транзакцию и не накладывать блокировку на набор (или ссылочный объект), если мы не обрабатываем данные в совокупности с подчиненными объектами (самим документом и дочерними регистрами), и нам не нужна гарантия согласованности этой совокупности. В моём примере мы открываем транзакцию, чтобы сохранить блокировку на наборе и исключить покушения других процессов на наш набор (а для задачи №2 ещё и исключить параллельную выгрузку объекта с одинаковым идентификатором).
 
Сравниваем версии (Хеш-суммы) переданной и текущей:
  • Если версия та же, значит клиентская транзакция завершилась успешно - выполняем постобработку
  • Если версии различаются, то причин две:
  1. был откат клиентской транзакции - значит ничего делать не надо
  2. пока мы пытались установить блокировку набор записей захватил другой процесс и успешно изменил его - значит тоже ничего не делаем, им займётся фоновое задание того другого процесса
Если все циклы закончились, а мы так и не смогли установить блокировку, значит мы имеем дело с аномально тяжёлым документом, несовместимым с принципом быстрых сообщений. Помещаем ссылку регистратора в специально заготовленный регистр сведений, играющий роль очереди, которую обрабатывает регламентное задание по расписанию, скажем раз в час и только в рабочее время. Если уж пользователь был готов ждать более 10 минут проведения документа, значит это не самый срочный документ, подождёт ещё час или до утра.
 
Если фоновое задание получило битую ссылку регистратора - значит пользователь сразу после создания нового документа нажал кнопку «Провести», документ выдал ошибку, а транзакция откатилась – ничего страшного, управляемая блокировка легко переваривает битые ссылки! Так же не возникает исключительных ситуаций при определении Хеш-суммы: набор записей возвращает пустую коллекцию, а БитаяСсылка.ПолучитьОбъект() возвращает Неопределено, всё легко сериализуется и хешируется.
 
Вывод:
Я предложил вариант триггера, который запускает фоновое задание сразу после завершения транзакции. Пользователи не почувствуют увеличения времени реакции системы, так как внутри пользовательской транзакции нет никаких записей или долгих вычислений, разве что сериализация объекта для вычисления версии, которую платформа должна делать быстро, потому что делает это регулярно при передаче данных между клиентским и серверным контекстами. Транзакция и блокировка внутри фонового задания - необязательны, зависит от решаемой задачи. Варианты использования я предложил в начале статьи. Как вы распорядитесь этой возможностью - решать вам! :-)

 

                           

Еще один вариант триггера.

Его идею подсказали в обсуждении под статьёй, мне она показалась интересной, но требующей предварительных испытаний под нагрузкой. Заключается в том, что если в транзакции записать новое регламентное задание с пустым расписанием, то оно выполниться сразу же, как закончится транзакция. Если транзакция откатилась, то РЗ не запишется и соответственно не выполнится. В параметры РЗ можно передать данные, которые требуется обработать сразу после завершения транзакции. А так же передать уникальный идентификатор регламентного задания, чтобы удалить его при выполнении фонового задания.

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

Основной минус такой - непонятно как поведёт себя сервер 1С в высоконагруженной базе. Если одновременно 1000 пользователей завершит транзакцию, как быстро будет запущена 1000 регламентных заданий? Боюсь что они попадут в некую очередь, и будут выполняться по мере освобождения ресурсов.

В любом случае идея интересная, и я точно буду её тестировать! :-)

           

 

Процедуру трансляции БУ-УУ ОбработатьДокумент( ) и процедуру выгрузки во внешнюю систему ВыгрузитьОбъект() я не привожу, это другая история, у каждого своя.

 
Для простоты восприятия привожу диаграмму происходящего в динамике:
 
 
 
Код для Задачи №1:

 

 
Код для Задачи №2:

 

Специальные предложения

Комментарии
Избранное Подписка Сортировка: Древо развёрнутое
Свернуть все
1. PerlAmutor 103 31.05.20 21:36 Сейчас в теме
Ой ой, запросы в цикле, да еще и бесконечном. И страшные какие. Текст запроса зачем-то каждый раз заново устанавливается. Почему бы не сгруппировать сначала результат, упорядочить по "РРР.Миллисекунды ВОЗР" и не взять "ПЕРВЫЕ 1", если он все-равно по приоритету выполняется последним? Зачем брать ХЭШ, когда есть свойство ВерсияДанных, которая меняется при любом изменении объекта?
vladimirmatancev; +1 Ответить
2. barelpro 1162 31.05.20 21:46 Сейчас в теме
(1)
Вот вбили на экзаменах в голову что запросы в цикле зло, и принимается как религиозный постулат ) А если этим запросом выполняется проверка очереди, которая динамически пополняется, и когда туда попал один объект несколько раз, нам надо его обработать один раз, как быть?

Про версию тоже не просто так: версия меняется только после завершения транзакции, а внутри транзакции она еще старая
3. zhichkin 721 01.06.20 02:11 Сейчас в теме
(2) Без обид. Просто читаю и плачу. Вашей вины в этом конечно же нет.
Удивительно каких только костылей не приходится придумывать к 1С ...
В данном случае конечно же напрашиваются асинхронные триггеры.
12. barelpro 1162 01.06.20 11:49 Сейчас в теме
(3)

Сервис брокер - интересный механизм! жалко что у вас только презентация и нет статьи с подробным разбором. Будет время досмотрю до конца и задам вопросы. Пока не совсем ясно, как вернуть событие завершения транзакции из сервис-брокера в 1С для запуска например фонового задания постобработки.
19. zhichkin 721 01.06.20 13:33 Сейчас в теме
(12) Как раз готовлю такую публикацию по использованию Service Broker в 1С. Думаю на этой неделе закончить и выпустить на следующей.
Пока не совсем ясно, как вернуть событие завершения транзакции из сервис-брокера в 1С для запуска например фонового задания постобработки.

Хранимая процедура активации пишется на C# - она вызывает, например, http-сервис 1C. Это если говорить о внтренней активации Service Broker. Кроме этого есть ещё внешняя активация через механизм Notifications SQL Server. Есть ещё и третий механизм через оператор SQL Server WAITFOR (RECEIVE ...FROM [Queue] TIMEOUT ...).
barelpro; +1 Ответить
20. barelpro 1162 01.06.20 13:35 Сейчас в теме
(19)
http-сервис - это долго, у меня быстрее )
Но вообще мне нравится, что вы копаете в направлении SQL и C# - большой респект!
22. zhichkin 721 01.06.20 13:47 Сейчас в теме
(20) Данные попадают в очередь. http-сервис нужен только для того, чтобы сообщить 1С, что появились сообщения. Дальше 1С сама разгребает очередь.
Если не http сервис, то можно из 1С поднять соединение по OLE DB и запросом вида WAITFOR (RECEIVE ...FROM [Queue] TIMEOUT ...) поместить в SQL Server своё ожидание сообщений из очереди. Это будет работать моментально как только завершится транзакция помещения первого сообщения в очередь.
TIMEOUT в данном случае указывает время ожидания первого сообщения в очереди, если она пустая.
WAITFOR фактически не создаёт нагрузки на SQL Server - это по сути "спящий" процесс.
23. barelpro 1162 01.06.20 13:53 Сейчас в теме
(22)

Так у меня тот же TIMEOUT - попытка блокировки в цикле, число циклов можно подбирать как и свойство базы "время ожидания блокировки". Само ожидание на блокировке - стандартный механизм 1С, он работает быстро.
И пока открывается OLE DB - соединение транзакция уже может завершиться, опять не вот тебе сразу.
Но как вариант, да, я понял идею, супер!
24. zhichkin 721 01.06.20 14:03 Сейчас в теме
(23) То, что Вы сделали - это очень круто!
Просто меня удручает, что 1С фактически заставляет постоянно искать какие-то недокументированные возможности. Тот же Service Broker работает уже 15 (!) лет, начиная с версии SQL Server 2005. Я пользуюсь Service Broker c 2007 года.
Если бы не лицензионное соглашение 1С я бы давно уже прикрутил асинхронные триггеры к 1С в виде типового документированного решения. Но увы.
Как сказала однажды моя жена: "Я поняла. 1С - это сексуальная ориентация".
Yashazz; Il; dabu-dabu; barelpro; +4 Ответить
26. barelpro 1162 01.06.20 14:08 Сейчас в теме
(24)
Я тоже рефлексирую по этому поводу, но за неимением горничной будем иметь... и подпольно использовать достижения внешнего мира))
zhichkin; +1 Ответить
29. barelpro 1162 01.06.20 14:58 Сейчас в теме
(24)
Кстати, раз уж заговорили о быстрой передаче сигнала между приложениями, подумайте на счет сетевых сокетов, там и подключение к каналу быстро устанавливается, и сама передача быстро идет....
30. zhichkin 721 01.06.20 15:18 Сейчас в теме
(29) Я думаю больше на тему gRPC сейчас. Там есть стриминг данных как раз через сокеты. Это протокол Google для организации взаимодействия между серверами на базе HTTP 2, кторый, кстати, Google и пропихивал очень активно.
31. zhichkin 721 01.06.20 15:21 Сейчас в теме
(29) Кроме этого у Microsoft для .NET есть технология Pipes как раз для взаимодействия между процессами, как на одной машине, так и на разных. Но ... во всех этих случаях, будь то Pipes или gRPC, нужно учитывать аспект целостности данных, а именно транзакции, чтобы случайно по дороге не потерять данные.
32. barelpro 1162 01.06.20 15:50 Сейчас в теме
(31)
Ну для быстрой отправки можно как-то выкрутиться средствами 1С, а для быстрой загрузки без внешних средств не обойтись. Например в коннекторе с Rabbit MQ от Серебрянной пули/БИТа каждые пять минут запускается регламентным заданием слушатель сетевых сокетов, нет ли в очереди сообщений...
33. zhichkin 721 01.06.20 16:02 Сейчас в теме
(32) Вечная проблема интегратора: что использовать "pull" или "push" и каким образом =) Мы какую задачу обсуждаем ? Обмен данными в реальном времени ? Абстрактно это не решается. Нужна конкретная задача и конкретные требования под неё. Я вижу, что Вы это понимаете как никто другой =)
34. nomad_irk 47 01.06.20 16:16 Сейчас в теме
(33)
Вечная проблема интегратора: что использовать "pull" или "push"

Лично я сторонник "pull" ибо негоже пихать что-либо куда-либо, если приемник к этому не готов(а) :)
35. zhichkin 721 01.06.20 16:21 Сейчас в теме
(34) Лично я не сторонник категоричных высказываний =) Интеграция - девушка с характером =)
37. barelpro 1162 01.06.20 16:23 Сейчас в теме
(34)
а я сторонник "быстро отправил и забыл", пусть посредники разбираются
39. nomad_irk 47 01.06.20 16:25 Сейчас в теме
(37)Одному мне вспомнилось:

"наше дело - не рожать, сунул - вынул и бежать!" ? :)
40. barelpro 1162 01.06.20 16:28 Сейчас в теме
(39)

хорошая поговорка ), но в случае интеграции получателей одного сообщения может быть много, почему об этом должен беспокоиться отправитель? По хорошему он вообще не должен знать сколько их, получателей.
41. nomad_irk 47 01.06.20 16:31 Сейчас в теме
(40)Для этих целей служит любая шина данных, но оно, как правило, в крупных компаниях. Мелкие компании выстраивают интеграцию чаще всего с помощью файлов и источник данных, как правило, при этом должен позаботится о каждом получателе.
42. barelpro 1162 01.06.20 16:51 Сейчас в теме
(41)

Полноценная ESB - да, не дешёвое удовольствие, но брокер сообщений типа Rabbit MQ всем по карману. Особенно после того, как БИТ выложил бесплатные исходники коннектора 1С-Rabbit MQ! )))
51. BabySG 04.06.20 12:43 Сейчас в теме
(42) ну, тут есть подсистема + компонента + возможность отказаться от регзаданий https://sbpg.atlassian.net/wiki/spaces/1C2RMQ/overview
И все бесплатно )
36. barelpro 1162 01.06.20 16:22 Сейчас в теме
(33)
Да мы просто вёдем светскую беседу ). Задача обеспечения доставки из контекста статьи выпадает.
С нетерпением ждём статьи использованию Service Broker в 1С!
38. zhichkin 721 01.06.20 16:23 Сейчас в теме
(36) Спасибо за интерес. Постараюсь не обмануть ожиданий =)
43. zhichkin 721 03.06.20 00:59 Сейчас в теме
(36) Выложил пример практического использования Service Broker на GitHub.
https://github.com/zhichkin/one-c-sharp-sql/tree/master/messaging/service-broker
Там есть:
- установочный скрипт SQL,
- демонстрационная обработка 1С,
- пример использования в коде SQL,
- результаты теста производительности.
barelpro; +1 Ответить
4. ardn 100 01.06.20 07:54 Сейчас в теме
В регистр тяжелых документов запросто могут попасть и нетяжелые.
Поправьте, если не прав, блокировка живет до окончания транзакции. Если менять пакет объектов в единой транзакции, например групповой обработкой, установленные искусственные блокировки будут долгими, все по этим объектам не обработается.
7. barelpro 1162 01.06.20 11:07 Сейчас в теме
(4)
Ну в рабочее время на боевой базе вряд ли кому-то придёт в голову надолго блокировать одной длинной транзакцией большое количество документов. Скорее всего разобьют на маленькие. А в нерабочее время - ну да, без спешки, пойдет обработка через очередь тяжёлых документов,
5. sam441 47 01.06.20 08:04 Сейчас в теме
Не знаю, чего на автора накинулись, мне показался подход интересным, благодарю.
barelpro; +1 Ответить
6. barelpro 1162 01.06.20 10:55 Сейчас в теме
(5)
Спасибо! Просто пока ещё не прдтянулись те, кто реально занимается интеграцией )
8. nomad_irk 47 01.06.20 11:11 Сейчас в теме
(6)Как по мне: в случае интеграций, нужно максимально использовать асинхронность. Лично меня пока не сможет никто убедить, что данные в интегрируемых системах нужны прям сию же секунду в случае использования транзакционных учетных систем.
9. barelpro 1162 01.06.20 11:14 Сейчас в теме
(8)
Так а чем фоновое задание, которое продолжает работать после проведения документа - не ассинхронность?
10. nomad_irk 47 01.06.20 11:23 Сейчас в теме
(9)Тем, что асинхронность - это два разных действия разнесенных по времени и транзакциям. Транзакция в данном конкретном случае - это само это фоновое задание, выполняющее проведение документа + еще какие-то действия.

Проводить документы и "складывать" эти документы в буффер для обработки их другим регл заданием и собственно другое регл. задание по обработке буффера - это есть асинхронность.

Провести документ и дальше выполнить обмен/выгрузку/еще что-то с этим самым документом в рамках одного регл задания - это синхронность.

Без буффера выполнять синхронизацию да еще и реал-тайм - такое себе.
11. barelpro 1162 01.06.20 11:42 Сейчас в теме
(10)
Хм... А вы поняли что в фоновом задании открывается вторая транзакция сразу, как закончилась первая в клиентском процессе?
13. nomad_irk 47 01.06.20 12:56 Сейчас в теме
(11)Понял. Это породит просто кучу транзакций передачи данных по каждому измененному объекту в рамках первой транзакции для какого-нибудь события типа восстановления последовательности.

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

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

В публикации упоминается варианты использования:
1. мгновенная синхронизация данных с другими учетными системами
2. мгновенное отражение в регл учете.

Разберем оба варианта использования, начнем со второго.

Регламентированный учет - не требует этого абсолютно. Регламентированный учет - следствие учета оперативного. Если бухгалтер увидит нужные цифры сразу - это ни холодно, ни жарко, это - никак, потому как суммы в проводках, так любимые бухгалтерами, будут в лучшем случае плановыми, либо вообще нулевыми ибо для реальных сумм нужен расчет с/с, если речь идет о таких учетных системах как ERP/УХ и прочих монстрах.

Мгновенная синхронизация в условиях транзакционных учетных систем - это по сути чушь, потому что для такого рода синхронизации нужна доступность удаленной базы в момент синхронизации. В случае такой синхронизации, если удаленная система по какой-то причине станет не доступной в момент проведения документа, что делать с данными, которые должны быть переданы, но не передались? Ответ: их нужно накапливать в неком "буффере", либо, спустя какое-то время, изменять исходные данные еще раз, чтобы инициализировать синхронизацию данных. Исходя из условий выполнения, придется еще раз выполнять изменение данных. Если таки накапливать данные для передачи в неком "буффере", то для чего вообще тогда весь этот сыр-бор с мгновенной синхронизацией данных?
14. barelpro 1162 01.06.20 13:16 Сейчас в теме
(13)
Я предложил вариант тригера, который запускает фоновое задание сразу после завершения транзакции. А как уж вы распорядитесь этой возможностью - решать вам.

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

Да, регламентный учет - посмертный учет, там оперативно только деньги умеют считать. А вот в управленческом учете важна оперативность, причем чтобы управленческие отчеты быстро строились, данные для них желательно предварительно подготовить. Вот вам еще одно применение этого тригера!

Давайте, включайте инженерный идеемёт! )))
15. acanta 01.06.20 13:22 Сейчас в теме
(14) Посмертный учет в моем понимании это после ликвидации предприятия. А как ведут на предприятии регламентный или управленческий - это зависит от бизнес процессов.
barelpro; +1 Ответить
18. nomad_irk 47 01.06.20 13:32 Сейчас в теме
(15) Лично мне не раз приходилось наблюдать, как из регл. учета пытаются делать упр учет, как это все работает не так как хотелось бы руководству :)
16. nomad_irk 47 01.06.20 13:23 Сейчас в теме
(14) ESB так же может быть недоступной, т.к. это такая же учетная система по своей сути.

Вижу, что вы меня не правильно поняли. Я НЕ ПРОТИВ вашего решения, я - ЗА, но с оговоркой, что это решение исключительно для действий внутри учетной системы, без привязки к синхронизации данных, т.к. в публикации указан один из двух примеров использования вашего варианта тригера именно для синхронизации данных ну и вы хотели услышать мнение тех, кто занимается интеграцией :)

А вот в управленческом учете важна оперативность, причем чтобы управленческие отчеты быстро строились, данные для них желательно предварительно подготовить. Вот вам еще дно применение этого тригера.


Вот это прям очень хороший пример. Потому что УУ, как правило, требует другие структуры хранения данных для отчетов, что предлагают типовые конфигурации и чтобы не ломать типовую конфигурацию, ваш вариант будет одним из вариантов решения трансформации данных для УУ отчетов.
barelpro; +1 Ответить
17. barelpro 1162 01.06.20 13:31 Сейчас в теме
(16)
если ESB не имеет онлайн-доступности, это не ESB а учётная система, как вы правильно сказали )
Онлайн доступность - это то ради чего существует само понятие шины или брокера сообщений
Но раз уж так случилось что ESB вдруг недоступна, ну тогда кладем в очередь "тяжелых документов" и обрабатываем по мере доступности получателя. Я ж говорю, в статье главный акцент именно на идее триггера после коммита транзакции, остальное ваше творчество.
21. nomad_irk 47 01.06.20 13:35 Сейчас в теме
(17)Вот вы и ответили на вопрос о том, какая это будет мгновенная синхронизация данных :)
И это - нормально в условиях транзакционных учетных систем.
25. barelpro 1162 01.06.20 14:04 Сейчас в теме
(21)
Сочувствую вашей боли! ))
Но поверьте, есть системы, где все работает, и собственники не скупятся вкладывать деньги в нормальные технологии!
27. nomad_irk 47 01.06.20 14:26 Сейчас в теме
(25)Да хоспади, не во вкладывании денег и не в нормальных технологиях проблемы, а в том, что ESB так же требует обслуживания, во время которого она не доступна, может навернутся сервер, обслуживающий ESB, может еще что-то.....
28. barelpro 1162 01.06.20 14:39 Сейчас в теме
(27)
Не, ну понятно, что в работе любой системы должны быть технологические окна, даже в 24*7. Саппорт - единственная профессия будущего, когда всё тотально будет автоматизировано )
44. shmalevoz 213 03.06.20 21:46 Сейчас в теме
Мы делали несколько иную схему реализации, хотя сама базовая идея была той же, блокировка и несколько потоков выполнения. Сделали несколько служебных регистров и писали данные в них, и на одном из них висели взаимоблокировки. А если что-то падало, то по разнице в регистрах можно было понято что обработано, а что осталось вне внимания.
Пи этом у вас несколько недоделано - ПослеЗавершенияТранзакции хорошо бы получал коллекцию объектов, которые в транзакции участвовали, если уж надо ловить такое событие, то обычно нужно понимать полную атомарность состава.

Даже примерный набросок схемы остался =))
45. shmalevoz 213 03.06.20 23:06 Сейчас в теме
Прошу простить, к предыдущему сообщению - не прикрепилась картинка

barelpro; +1 Ответить
46. barelpro 1162 04.06.20 00:30 Сейчас в теме
(45)

Да, насчет атомарности состава - правильное замечание, но тут всё зависит от совокупности данных, с которыми мы собираемся работать после транзакции, у каждого свой кейс.
Вообще моей идее ровно неделя, чем дальше, тем интересней, уже поймал интересную фичу - есть такой регистр сведений ДополнительныеСведения, он отвечает за механизм допсведений в типовых конфигурациях. Когда пользователь меняет сразу несколько допсведений в одном объекте, в подписке в наборе один порядок записей, а после завершения транзакции уже другой, и хеши не совпадают, хотя по содержания наборы идентичны! В общем, тут еще пилить и пилить!
Хорошо что вы придумали такой же механизм, жалко что не написали статью 8-)
47. shmalevoz 213 04.06.20 00:43 Сейчас в теме
(46)
Там конечно с подводными камнями не все просто... Что есть то есть =) Многократная запись объекта в одной транзакции чего только стоит =)
Подвычищу код от лишнего и наверное выложу конфигурацию и статью, а то сейчас там многовато сопутствующих всяких вызовов под другую задачу.
58. shmalevoz 213 09.06.20 09:29 Сейчас в теме
(46)
Выделил реализацию в чистое решение, выложил статью и решение
Реализация программного события ПослеЗавершенияТранзакции
надеюсь пригодится. Решение проверено экслуатацией.
48. asved.ru 35 04.06.20 09:04 Сейчас в теме
Менеджер сервиса технологии 1С:Фреш, ВыполнитьПослеТранзакции()
shmalevoz; +1 Ответить
49. shmalevoz 213 04.06.20 11:18 Сейчас в теме
(48) Глянул код в Менеджере сервиса, снимаю шляпу перед автором идеи. Намного проще, стабильней и понятней. За неимением платформенного события конечно тоже костылик, но намного более качественный. Регламентные задания для определения.... Вот что значит использовать правильные объекты для реализации задачи =)
50. barelpro 1162 04.06.20 11:38 Сейчас в теме
(49)
Тоже хочу посмотреть, не у всех есть доступ к дистрибутиву Фреш )
54. asved.ru 35 04.06.20 14:47 Сейчас в теме
(50) Вкратце - используется непредопределенное регламентное задание, создаваемое внутри транзакции. Как только транзакция зафиксируется, менеджер заданий его выполнит, а если она откатится - не было никакого задания. Ну и убраться за собой.
52. shmalevoz 213 04.06.20 13:00 Сейчас в теме
Сначала о возможных проблемах типового варианта, потом будут выдержки из типового кода, вдруг забанят =)
Главной проблемой видится невозможность контроля расписания выполнения Регламентных заданий, а поскольку там все опирается на них, то опять же получается невозможно автоматом нормально собрать атомарный состав транзакции. Сами 1С тоже об этом прямо пишут
Сами 1С об этом тоже прямо пишут
ни в каких случаях не следует задавать периодичность выполнения регламентных заданий меньше одной минуты;

И кажется вполне возможной ситуация, когда (скажем накопление сведений происходит из событий ПриЗаписи)
Объект.Записать()
// 5 секунд
Объект1.Записать()

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

Реализации в несколько потоков в ведут себя значительно лучше в первом моменте и совсем лишены второго.
53. shmalevoz 213 04.06.20 13:35 Сейчас в теме
И выдержки из менеджера сервиса

// Привилегированным режимом обрамлены обращения к РегламентныеЗадания. Для краткости
УстановитьПривилегированныйРежим(Истина);

ЗаданиеМетаданные	= Метаданные.РегламентныеЗадания.ПослеТранзакции;

// Задания постобработки текущего сеанса 
ЗаданияОтбор = Новый Структура;
ЗаданияОтбор.Вставить("Метаданные", ЗаданиеМетаданные);
ЗаданияОтбор.Вставить("Ключ", Формат(НомерСеансаИнформационнойБазы(), "ЧГ=0"));
ЗаданияОтбор.Вставить("Использование", Истина);

ТранзакцияЗадание	= Неопределено;
ОбновлениеЭто		= Ложь;
ОшибкаТекст			= "";

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

// Страхуемся на случай, если вдруг задание начнет выполняться в то время, пока его обновляем
Пока Истина Цикл
	ВызовыТаблица	= Неопределено;
	Если ОбновлениеЭто Тогда
		// Сериализация для таблицы, массив, или например структуру можно было бы и напрямую
		ВызовыТаблица	= ЗаданиеВызовыТаблицаДесериализовать(ТранзакцияЗадание.Параметры.Получить(0));
	Иначе
		ТранзакцияЗадание = РегламентныеЗадания.СоздатьРегламентноеЗадание(ЗаданиеМетаданные);
		ВызовыТаблица	= ЗаданиеВызовыТаблицаСоздать();
	КонецЕсли; 
	// Здесь всякое обновление параметров задания - добавление при необходимости новой точки выполнения, ....
	//
	ТранзакцияЗадание.Параметры.Очистить();
	ТранзакцияЗадание.Параметры.Добавить(ЗаданиеВызовыТаблицаСериализовать(ВызовыТаблица));
	// Самое интересное - вдруг пока возились задание уже пропало =)
	Если ОбновлениеЭто 
		И РегламентныеЗадания.НайтиПоУникальномуИдентификатору(ТранзакцияЗадание
		.УникальныйИдентификатор) = Неопределено Тогда
		ТранзакцияЗадание	= Неопределено;
		ОбновлениеЭто		= Ложь;
		Продолжить;
	КонецЕсли; 
	// Все гуд, обновляем данные
	ТранзакцияЗадание.Записать();
	Прервать;
КонецЦикла; 

Показать


Примерно вкратце вот так. Для своего кейса конечно решение отличное, в сервисе нет мгновенного обмена с управляемыми базами, там задержки нормальное явление, и необходимо просто гарантированно что-то вызвать после транзакции (скорее всего обмен), но не всем кейсам это подойдет =)
А если нужна оперативность и/или сбор состава транзакции, то имхо схема с несколькими потоками предпочтительней, несмотря на более сложную реализацию.
JohnyDeath; +1 Ответить
55. barelpro 1162 04.06.20 15:02 Сейчас в теме
(53)
Ага, для каждого пользовательского сеанса создается отдельное регл задание. Но не понятно, с какой периодичностью запускаются регл задания? И код регл задания тоже интересно посмотреть. Похоже что оно выполняется постоянно, и слушает в цикле какую -то очередь - там самый смысл метода.
В общем одни загадки...
56. shmalevoz 213 04.06.20 15:13 Сейчас в теме
(55)
Исходя из опыта допила Фреша, то как раз примерно раз в минуту, там была масса проблем с частотой запуска асинхронного обмена.
А код задания достаточно прост, в него параметрами приходит таблица очереди вызовов и дергаются переданные в очереди методы. Ну плюс там число попыток, и прочая сервисная обвязка.
57. barelpro 1162 04.06.20 15:46 Сейчас в теме
(56)
Если для каждого номера сеанса создается отдельное регл задание - представляю как выглядит таблица регл заданий, ведь ее потом никто не чистит )
Вообще тут не спроста используется ЗаблокироватьДанныеДляРедактирования, это костыль - потому что по другому нельзя убедиться, что параллельно это же задание не записывается в другом процессе и мы не словим блокировку или измененную версию при записи, т.к. таблица регл заданий - это обычный ссылочный объект, как справочник или документ.
И что делает регл задание, если оно запустилось, а транзакция, породившая его еще не закончилась? Ждать следующего запуска?
Ну и периодичность запуска регл задания - тут тоже слабое место. А если все пользователи выйдут из базы, а куча регл заданий останется и будет запускаться, то получится как описано здесь https://infostart.ru/public/996126/

Забавно, но я до метода (который описан в статье) использовал именно регл задания, создавал, перезаписывал, управлял расписанием, и отказался, потому что нашел более быстрый метод )
Оставьте свое сообщение

См. также

Публикаций не найдено

Попробуйте расширить область поиска, проверьте поисковый запрос и повторите попытку.

Или закажите индивидуальную разработку вашего решения.

Создать заказ на разработку