Интегратсияи услуби BPM

Интегратсияи услуби BPM

Салом, Хабр!

Ширкати мо дар таҳияи қарорҳои нармафзори дараҷаи ERP тахассус дорад, ки дар он ҳиссаи асосиро системаҳои транзаксионӣ бо миқдори зиёди мантиқи тиҷорӣ ва ҷараёни кории ла EDMS ишғол мекунанд. Версияҳои муосири маҳсулоти мо ба технологияҳои JavaEE асос ёфтаанд, аммо мо инчунин бо микросервисҳо фаъолона озмоиш карда истодаем. Яке аз самтҳои мушкилтарини чунин ҳалли интегратсияи зерсистемаҳои гуногуни марбут ба доменҳои ҳамсоя мебошад. Вазифаҳои ҳамгироӣ новобаста аз услубҳои меъморӣ, стекҳои технологӣ ва чаҳорчӯбаҳое, ки мо истифода мебарем, ҳамеша ба мо дарди сар меоварданд, аммо вақтҳои охир дар ҳалли чунин мушкилот пешрафт ба назар мерасад.

Дар мақолае, ки ба диққати шумо оварда шудааст, ман дар бораи таҷриба ва тадқиқоти меъмории NPO Криста дар минтақаи таъиншуда сӯҳбат мекунам. Мо инчунин мисоли ҳалли оддии мушкилоти интегратсияро аз нуқтаи назари таҳиягари барнома баррасӣ мекунем ва мефаҳмем, ки дар паси ин соддагӣ чӣ пинҳон аст.

Радди масъулият

Қарорҳои меъморӣ ва техникии дар мақола тавсифшуда аз ҷониби ман дар асоси таҷрибаи шахсӣ дар заминаи вазифаҳои мушаххас пешниҳод карда мешаванд. Ин қарорҳо даъвои универсалӣ надоранд ва дар шароити дигари истифода оптималӣ буда наметавонанд.

BPM бо он чӣ иртибот дорад?

Барои ҷавоб додан ба ин савол, мо бояд каме ба мушаххасоти масъалаҳои татбиқшавандаи ҳалли мо омӯзем. Қисми асосии мантиқи тиҷорӣ дар системаи маъмулии транзаксионии мо ворид кардани маълумот ба пойгоҳи додаҳо тавассути интерфейсҳои корбар, ба таври дастӣ ва ба таври худкор тафтиш кардани ин додаҳо, интиқол додани он тавассути ягон ҷараёни корӣ, интишори он ба системаи дигар / махзани аналитикӣ / бойгонӣ, тавлиди ҳисоботҳо мебошад. Ҳамин тариқ, вазифаи асосии система барои муштариён автоматикунонии равандҳои тиҷорати дохилии онҳо мебошад.

Барои роҳат, мо истилоҳи "ҳуҷҷат" -ро дар муошират ҳамчун як абстраксияи маҷмӯи додаҳо истифода мебарем, ки бо калиди умумӣ муттаҳид шудааст, ки ба он ҷараёни мушаххаси кориро "замима кардан" мумкин аст.
Аммо дар бораи мантиқи ҳамгироӣ чӣ гуфтан мумкин аст? Дар ниҳоят, вазифаи ҳамгироӣ аз ҷониби меъмории система ба вуҷуд меояд, ки он ба қисмҳо НЕ бо дархости фармоишгар, балки таҳти таъсири омилҳои тамоман гуногун "арра шудааст":

  • дар зери таъсири қонуни Конвей;
  • дар натичаи истифодаи такрории зерсистемахое, ки пештар барои дигар махсулот кор карда шудаанд;
  • чунон ки меъмор дар асоси талаботи гайрифунксионалй карор додааст.

Васвасаи бузурге барои ҷудо кардани мантиқи ҳамгироӣ аз мантиқи тиҷоратии ҷараёни асосии корӣ вуҷуд дорад, то мантиқи тиҷоратро бо артефактҳои ҳамгироӣ ифлос накунад ва таҳиягари барномаро аз омӯхтани хусусиятҳои манзараи меъмории система наҷот диҳад. Ин равиш як қатор афзалиятҳо дорад, аммо амалия бесамар будани онро нишон медиҳад:

  • ҳалли мушкилоти ҳамгироӣ одатан ба соддатарин вариантҳо дар шакли зангҳои синхронӣ бо сабаби маҳдуд будани нуқтаҳои васеъшавӣ дар татбиқи ҷараёни асосии корӣ (бештар дар бораи камбудиҳои ҳамгироии синхронӣ дар поён);
  • артефактҳои ҳамгироӣ то ҳол ба мантиқи асосии тиҷорат ворид мешаванд, вақте ки фикру мулоҳиза аз зерсистемаи дигар зарур аст;
  • таҳиягари барнома интегратсияро нодида мегирад ва метавонад бо тағир додани ҷараёни кор онро ба осонӣ вайрон кунад;
  • система аз нуқтаи назари корбар як ягонаи ягона буданро қатъ мекунад, "дарзҳо" байни зерсистемаҳо намоён мешаванд, амалиёти зиёдатии корбар пайдо мешаванд, ки интиқоли маълумотро аз як зерсистемаи дигар оғоз мекунанд.

Равиши дигар ин баррасӣ кардани ҳамкориҳои ҳамгироӣ ҳамчун ҷузъи ҷудонашавандаи мантиқи асосии тиҷорат ва ҷараёни корӣ мебошад. Барои нигоҳ доштани талаботҳои маҳорати таҳиягарони барномаҳо аз болоравии баланд, эҷоди ҳамгироии нави ҳамгироӣ бояд ба осонӣ ва табиӣ бо имконоти ҳадди ақали интихоби ҳалли мушкилот анҷом дода шавад. Ин назар ба он, ки ба назар мерасад, душвортар аст: асбоб бояд ба қадри кофӣ тавоно бошад, ки ба корбар имконоти зарурии истифодаи онро фароҳам оварад ва дар айни замон имкон надиҳад, ки ба пои худ тир афтанд. Саволҳои зиёде мавҷуданд, ки муҳандис бояд дар заминаи вазифаҳои ҳамгироӣ ҷавоб диҳад, аммо таҳиягари барнома набояд дар кори ҳаррӯзаи худ дар бораи он фикр кунад: ҳудуди транзаксия, мувофиқат, атомӣ, амният, миқёс, тақсимоти сарборӣ ва захираҳо, масир, маршализатсия, паҳнкунӣ ва ивазкунии контекстҳо ва ғайра. Ба таҳиягарони барнома қолабҳои қабули қарорҳои хеле содда пешниҳод кардан лозим аст, ки дар онҳо ҷавобҳо ба ҳамаи ин саволҳо аллакай пинҳон карда шудаанд. Ин намунаҳо бояд ба қадри кофӣ бехатар бошанд: мантиқи тиҷорат зуд-зуд тағир меёбад, ки хатари ворид кардани хатогиҳоро зиёд мекунад, арзиши хатогиҳо бояд дар сатҳи хеле паст боқӣ монанд.

Аммо ба ҳар ҳол, BPM бо он чӣ кор дорад? Имкониятҳои зиёде барои татбиқи ҷараёни корӣ мавҷуданд ...
Дар ҳақиқат, татбиқи дигари равандҳои бизнес дар ҳалли мо хеле маъмул аст - тавассути танзими декларативии диаграммаи гузариши давлатӣ ва пайваст кардани коркардкунандагон бо мантиқи тиҷорат ба гузариш. Дар баробари ин давлате, ки мавкеи имрузаи «хуччат»-ро дар процесси кор муайян мекунад, атрибути худи «хуччат» мебошад.

Интегратсияи услуби BPM
Дар оғози лоиҳа ин раванд ба назар мерасад

Маъруфияти чунин татбиқ бо соддагии нисбӣ ва суръати эҷоди равандҳои хаттии бизнес вобаста аст. Бо вуҷуди ин, вақте ки системаҳои нармафзор мураккабтар мешаванд, қисми автоматикунонидашудаи раванди бизнес афзоиш меёбад ва мураккабтар мешавад. Зарурати декомпозитсия, истифодаи такрории қисмҳои равандҳо ва инчунин равандҳои форинг вуҷуд дорад, то ҳар як шоха дар баробари иҷро карда шавад. Дар ин гуна шароит асбоб номувофиқ мешавад ва диаграммаи гузариши ҳолат мазмуни иттилоотии худро гум мекунад (таъсири мутақобилаи интегратсионӣ дар диаграмма умуман инъикос намеёбад).

Интегратсияи услуби BPM
Ин раванд пас аз чанд такрори аниќ кардани талабот ба назар мерасад

Рохи баромадан аз ин вазъият интеграцияи двигатель буд jBPM ба баъзе маҳсулот бо равандҳои мураккабтарини тиҷорат. Дар муддати кӯтоҳ, ин ҳалли каме муваффақият ба даст овард: имкон дод, ки равандҳои мураккаби тиҷоратӣ ҳангоми нигоҳ доштани диаграммаи хеле иттилоотӣ ва муосир дар қайдҳо амалӣ карда шаванд. BPMN2.

Интегратсияи услуби BPM
Қисми хурди раванди мураккаби тиҷорат

Дар муддати тӯлонӣ, ҳалли он ба интизориҳо мувофиқат накард: шиддатнокии баланди меҳнати эҷоди равандҳои тиҷоратӣ тавассути асбобҳои визуалӣ имкон намедиҳад, ки нишондиҳандаҳои қобили қабули ҳосилнокӣ ба даст оварда шаванд ва худи асбоб яке аз чизҳои нописанди байни таҳиягарон гардид. Дар бораи сохти дохилии двигатель низ шикоятхо ба амал омаданд, ки ин боиси пайдо шудани бисьёр «патчахо» ва «асгабчахо» гардид.

Ҷанбаи асосии мусбати истифодаи jBPM дарк кардани фоида ва зарари доштани ҳолати доимии худ барои мисоли раванди тиҷорат буд. Мо инчунин имкони истифодаи равиши равандро барои татбиқи протоколҳои мураккаби ҳамгироӣ байни замимаҳои гуногун бо истифода аз ҳамкории асинхронӣ тавассути сигналҳо ва паёмҳо дидем. Дар ин бобат мавчудияти давлати устувор роли халкунанда мебозад.

Дар асоси гуфтаҳои боло, мо метавонем хулоса кунем: Муносибати раванд дар услуби BPM ба мо имкон медиҳад, ки доираи васеи вазифаҳоро оид ба автоматикунонии равандҳои мураккабтари бизнес ҳал кунем, фаъолиятҳои интегратсияро ба ин равандҳо ҳамоҳанг созем ва қобилияти намоиши визуалии раванди татбиқшударо дар аломати мувофиқ нигоҳ дорем.

Камбудиҳои зангҳои синхронӣ ҳамчун намунаи ҳамгироӣ

Интегратсияи синхронӣ ба соддатарин занги блоккунӣ дахл дорад. Як зерсистема ҳамчун тарафи сервер амал мекунад ва API-ро бо усули дилхоҳ фош мекунад. Зерсистемаи дигар ҳамчун ҷониби муштарӣ амал мекунад ва дар вақти лозима бо интизории натиҷа занг мезанад. Вобаста аз меъмории система, паҳлӯҳои муштарӣ ва сервер метавонанд ё дар як барнома ва раванд ё дар дигарҳо ҷойгир шаванд. Дар ҳолати дуюм, шумо бояд каме татбиқи RPC-ро истифода баред ва маршализатсияи параметрҳо ва натиҷаи зангро таъмин кунед.

Интегратсияи услуби BPM

Чунин шакли ҳамгироӣ дорои маҷмӯи хеле зиёди нуқсонҳо мебошад, аммо аз сабаби содда будани он дар амалия хеле васеъ истифода мешавад. Суръати татбиќ љолиб аст ва шуморо водор мекунад, ки онро дар шароити мўњлатњои "сухтан" такрор ба такрор ба кор баред, њалли онро ба ќарзи техникї нависед. Аммо чунин мешавад, ки таҳиягарони бетаҷриба онро бидуни огоҳӣ истифода мебаранд, танҳо оқибатҳои манфиро дарк намекунанд.

Илова ба афзоиши равшани пайвастагии зерсистемаҳо, мушкилоти камтар ошкор бо транзаксияҳои "паҳншавӣ" ва "дароз" вуҷуд доранд. Воқеан, агар мантиқи тиҷорат ягон тағирот ворид кунад, пас транзаксияҳо ҳатмӣ мебошанд ва транзаксияҳо, дар навбати худ, захираҳои муайяни замимаро, ки аз ин тағирот зарар дидаанд, маҳкам мекунанд. Яъне то он даме, ки як зерсистема посухи дигареро интизор нашавад, вай наметавонад транзаксияро анҷом диҳад ва қулфҳоро озод кунад. Ин хатари таъсироти гуногунро ба таври назаррас зиёд мекунад:

  • вокуниши система гум мешавад, корбарон барои посух ба дархостҳо муддати тӯлонӣ интизор мешаванд;
  • сервер умуман вокуниш ба дархостҳои корбарро аз сабаби ҳавзи пур аз ришта қатъ мекунад: аксари риштаҳо дар қулфи захираи ишғолкардаи транзаксия "меистанд";
  • бунбастҳо ба миён меоянд: эҳтимолияти пайдоиши онҳо аз давомнокии муомилот, миқдори мантиқи тиҷорат ва қуфлҳо дар муомилот вобаста аст;
  • хатогиҳои ба охир расидани мӯҳлати транзаксия пайдо мешаванд;
  • сервер ба OutOfMemory "афтад" агар вазифа коркард ва тағир додани миқдори зиёди маълумотро талаб кунад ва мавҷудияти интегратсияҳои синхронӣ тақсим кардани коркардро ба транзаксияҳои "сабуктар" хеле мушкил мекунад.

Аз нуқтаи назари меъморӣ, истифодаи бастани зангҳо ҳангоми ҳамгироӣ боиси аз даст додани назорати сифати зерсистемаҳои алоҳида мегардад: дар алоҳидагӣ аз ҳадафҳои сифати зерсистемаи дигар таъмин намудани ҳадафҳои сифатии як зерсистема ғайриимкон аст. Агар зерсистемаҳо аз ҷониби дастаҳои гуногун таҳия карда шаванд, ин мушкилоти калон аст.

Корҳо боз ҳам ҷолибтар мешаванд, агар зерсистемаҳои ҳамгирошуда дар замимаҳои гуногун бошанд ва дар ҳарду ҷониб тағиротҳои синхронӣ ворид карда шаванд. Чӣ тавр ин тағиротҳоро транзаксионӣ кардан мумкин аст?

Агар тағирот дар транзаксияҳои алоҳида ворид карда шаванд, он гоҳ коркарди устувори истисноҳо ва ҷуброн бояд таъмин карда шавад ва ин бартарии асосии ҳамгироии синхронӣ - соддаиро комилан аз байн мебарад.

Амалиётҳои тақсимшуда низ ба хотир меоянд, аммо мо онҳоро дар ҳалли худ истифода намебарем: таъмини эътимоднокӣ душвор аст.

"Сага" ҳамчун роҳи ҳалли мушкилоти муомилот

Бо маъруфияти афзояндаи хидматрасонии микросервисҳо, талабот ба онҳо афзоиш меёбад Намунаи Saga.

Ин намуна мушкилоти дар боло зикршудаи муомилоти дарозмуддатро ба таври комил ҳал мекунад ва инчунин имконоти идоракунии ҳолати системаро аз ҷониби мантиқи тиҷорат васеъ мекунад: ҷубронпулӣ пас аз муомилоти номуваффақ метавонад системаро ба ҳолати аввалааш баргардонад, балки алтернатива пешниҳод кунад. роҳи коркарди маълумот. Он инчунин ба шумо имкон медиҳад, ки қадамҳои бомуваффақияти коркарди маълумотро такрор накунед, вақте ки шумо кӯшиш мекунед, ки равандро ба анҷоми "хуб" расонед.

Ҷолиб он аст, ки дар системаҳои монолитӣ, ин намуна инчунин ҳангоми ҳамгироии зерсистемаҳои возеҳ алоқаманд аст ва таъсири манфие вуҷуд дорад, ки аз транзаксияҳои тӯлонӣ ва қуфлҳои дахлдори захираҳо ба вуҷуд меоянд.

Дар робита ба равандҳои тиҷоратии мо дар услуби BPM, татбиқи Сагаҳо хеле осон ба назар мерасад: қадамҳои инфиродии Сагаҳо метавонанд ҳамчун фаъолият дар доираи раванди тиҷорат муқаррар карда шаванд ва ҳолати доимии раванди бизнес, дар байни дигар чизхо, вазъияти дохилии Сагахо. Яъне мо ба ягон механизми иловагии ҳамоҳангсозӣ ниёз надорем. Ба шумо танҳо як брокери паёмӣ лозим аст, ки кафолати "ҳадди ақал як маротиба" ҳамчун нақлиётро дастгирӣ мекунад.

Аммо чунин ҳалли низ "нарх"-и худро дорад:

  • мантиқи тиҷорат мураккабтар мешавад: шумо бояд ҷубронпулиро кор кунед;
  • аз консентратсияи пурра даст кашидан лозим аст, ки он метавонад махсусан барои системаҳои монолитӣ ҳассос бошад;
  • меъморӣ каме мураккабтар мешавад, зарурати иловагӣ ба брокери паём вуҷуд дорад;
  • воситаҳои иловагии мониторинг ва идоракунӣ талаб карда мешаванд (гарчанде ки дар маҷмӯъ ин ҳатто хуб аст: сифати хидматрасонии система баланд мешавад).

Барои системаҳои монолитӣ, асоснокии истифодаи "Sags" он қадар равшан нест. Барои микросервисҳо ва дигар SOAҳо, ки дар он ҷо эҳтимолан брокер вуҷуд дорад ва мутобиқати пурра дар оғози лоиҳа қурбон карда шудааст, манфиатҳои истифодаи ин намуна метавонад аз нуқсонҳо зиёдтар бошад, хусусан агар дар API қулай мавҷуд бошад. сатҳи мантиқи тиҷорат.

Инкапсуляцияи мантиқи тиҷорат дар хидматрасониҳои хурд

Вақте ки мо ба озмоиш бо хидматҳои микросервис оғоз кардем, як саволи оқилона ба миён омад: мантиқи тиҷорати доменро дар робита бо хидмате, ки устувории додаҳои доменро таъмин мекунад, дар куҷо гузоштан мумкин аст?

Ҳангоми дидан ба меъмории гуногуни BPMS, ҷудо кардани мантиқи тиҷорӣ аз субот метавонад оқилона ба назар расад: як қабати хидматрасонии платформа ва мустақили домен эҷод кунед, ки муҳит ва контейнерро барои иҷрои мантиқи тиҷорати домен ташкил медиҳанд ва устувории додаҳои доменро ҳамчун як ҷузъи алоҳида ташкил кунед. қабати микросервисҳои хеле содда ва сабук. Равандҳои тиҷоратӣ дар ин ҳолат хидматҳои қабати устуворро ташкил медиҳанд.

Интегратсияи услуби BPM

Ин равиш як плюси хеле калон дорад: шумо метавонед функсионалии платформаро ба қадри дилхоҳатон зиёд кунед ва аз ин танҳо қабати мувофиқи микросервисҳои платформа "фарбеҳ мешавад". Равандҳои тиҷорӣ аз ҳама доменҳо фавран имкон пайдо мекунанд, ки функсияҳои нави платформаро пас аз навсозӣ истифода баранд.

Таҳқиқоти муфассалтар камбудиҳои назарраси ин равишро ошкор кард:

  • хидмати платформае, ки мантиқи тиҷорати бисёр доменҳоро якбора иҷро мекунад, ҳамчун як нуқтаи ноком хатарҳои бузург дорад. Тағйироти зуд-зуд дар мантиқи тиҷорат хатари хатогиҳоро, ки боиси нокомии тамоми система мешаванд, зиёд мекунад;
  • масъалаҳои иҷроиш: мантиқи тиҷорат бо маълумоти он тавассути интерфейси танг ва суст кор мекунад:
    • додаҳо бори дигар ҷамъ карда мешаванд ва тавассути стеки шабака интиқол дода мешаванд;
    • хидмати домен аксар вақт маълумоти бештареро бармегардонад, ки мантиқи тиҷорӣ барои коркард талаб мекунад, аз сабаби қобилияти нокифояи параметрсозии дархост дар сатҳи API-и берунии хидмат;
    • якчанд қисмҳои мустақили мантиқи тиҷорӣ метавонанд такроран як маълумотро барои коркард дубора дархост кунанд (шумо метавонед ин мушкилотро тавассути илова кардани лӯбиёи сеанс, ки маълумоти кэш мекунанд, сабук кунед, аммо ин меъмориро боз ҳам мушкилтар мекунад ва мушкилоти тозагии додаҳо ва беэътибор кардани кэшро ба вуҷуд меорад);
  • масъалаҳои муомилот:
    • равандҳои тиҷоратӣ бо ҳолати доимии аз ҷониби хидмати платформа нигоҳ дошташуда бо маълумоти домен мувофиқат намекунанд ва роҳҳои осони ҳалли ин мушкилот вуҷуд надоранд;
    • интиқол додани қулфи додаҳои домен аз транзаксия: агар мантиқи тиҷорати домен бояд тағирот ворид кунад, пас аз аввал тафтиш кардани дурустии маълумоти воқеӣ, имкони тағирёбии рақобатпазир дар маълумоти коркардшударо истисно кардан лозим аст. Бастани берунии додаҳо метавонад ба ҳалли мушкилот мусоидат кунад, аммо чунин ҳалли хатарҳои иловагӣ дорад ва эътимоднокии умумии системаро коҳиш медиҳад;
  • мушкилиҳои иловагӣ ҳангоми навсозӣ: дар баъзе ҳолатҳо, шумо бояд хидмати суботкорӣ ва мантиқи тиҷоратиро синхронӣ ё бо пайдарпаии қатъӣ навсозӣ кунед.

Дар ниҳоят, ба ман лозим омад, ки ба асосҳо баргардам: маълумоти домен ва мантиқи тиҷорати доменро ба як хидматрасонии хурд дохил кунед. Ин равиш дарки микросервисро ҳамчун ҷузъи ҷудонашавандаи система содда мекунад ва боиси мушкилоти дар боло зикршуда намегардад. Ин ҳам ройгон нест:

  • Стандартизатсияи API барои ҳамкорӣ бо мантиқи тиҷорӣ (аз ҷумла, барои таъмини фаъолияти корбарон ҳамчун як қисми равандҳои бизнес) ва хидматҳои платформаи API талаб карда мешавад; таваҷҷӯҳи бештар ба тағйироти API, мутобиқати пеш ва аќиб талаб карда мешавад;
  • илова кардани китобхонаҳои иловагии вақти корӣ барои таъмини кори мантиқи тиҷорӣ ҳамчун як қисми чунин микросервис талаб карда мешавад ва ин талаботҳои навро барои чунин китобхонаҳо ба вуҷуд меорад: сабукӣ ва ҳадди аққали вобастагии гузаранда;
  • таҳиягарони мантиқи тиҷорӣ бояд версияҳои китобхонаҳоро пайгирӣ кунанд: агар микросервис муддати тӯлонӣ анҷом наёфта бошад, пас он эҳтимолан версияи кӯҳнаи китобхонаҳоро дар бар мегирад. Ин метавонад як монеаи ғайричашмдошт барои илова кардани хусусияти нав бошад ва метавонад талаб кунад, ки мантиқи тиҷоратии кӯҳнаи чунин хидмат ба версияҳои нави китобхонаҳо интиқол дода шавад, агар дар байни версияҳо тағйироти номувофиқ вуҷуд дошта бошанд.

Интегратсияи услуби BPM

Дар чунин меъморӣ як қабати хидматҳои платформа низ мавҷуд аст, аммо ин қабат дигар контейнерро барои иҷрои мантиқи тиҷорати домен ташкил намекунад, балки танҳо муҳити он, ки функсияҳои ёрирасони "платформа"-ро таъмин мекунад. Чунин қабат на танҳо барои нигоҳ доштани сабукии микросервисҳои домен, балки барои мутамаркази идоракунӣ зарур аст.

Масалан, фаъолияти корбарон дар равандҳои тиҷоратӣ вазифаҳоро ба вуҷуд меорад. Бо вуҷуди ин, ҳангоми кор бо супоришҳо, корбар бояд вазифаҳоро аз ҳама доменҳо дар рӯйхати умумӣ бубинад, ки маънои онро дорад, ки хидмати платформаи сабти вазифаҳои мувофиқ, ки аз мантиқи тиҷорати домен тоза карда шудааст, вуҷуд дорад. Нигоҳ доштани фарогирии мантиқи тиҷорат дар ин замина хеле мушкил аст ва ин як созиши дигари ин меъморӣ аст.

Интегратсияи равандҳои тиҷоратӣ аз нигоҳи таҳиягари барнома

Тавре ки дар боло зикр гардид, таҳиягари барнома бояд аз хусусиятҳои техникӣ ва муҳандисии амалисозии ҳамкории якчанд барномаҳо абстракт карда шавад, то ба ҳосилнокии хуби рушд эътимод дошта бошад.

Биёед кӯшиш кунем, ки як масъалаи мураккаби ҳамгироиро, ки махсус барои мақола ихтироъ шудааст, ҳал кунем. Ин як вазифаи "бозӣ" хоҳад буд, ки се барномаро дар бар мегирад, ки дар он ҳар кадоми онҳо номи домейнро муайян мекунанд: "app1", "app2", "app3".

Дар дохили ҳар як барнома, равандҳои бизнес оғоз мешаванд, ки тавассути автобуси ҳамгироӣ ба "тӯббозӣ" оғоз мекунанд. Паёмҳо бо номи "Тӯб" ҳамчун тӯб амал мекунанд.

Қоидаҳои бозии:

  • бозигари якум ташаббускор аст. Вай бозигарони дигарро ба бозӣ даъват мекунад, бозиро оғоз мекунад ва ҳар вақт метавонад онро хотима диҳад;
  • дигар бозигарон иштироки худро дар бозй эълон мекунанд, бо хамдигар ва бозингари якум «шинос мешаванд»;
  • пас аз гирифтани туб бозигар бозигари дигари иштироккунандаро интихоб мекунад ва тубро ба у медихад. Шумораи умумии гузаришҳо ҳисоб карда мешавад;
  • ҳар як бозигар "энергия" дорад, ки бо ҳар як гузариш аз ҷониби он бозигар кам мешавад. Вақте ки қувваи барқ ​​тамом мешавад, плеер аз бозӣ хориҷ карда мешавад, ки ба нафақа баромадани худро эълон мекунад;
  • агар бозигар танҳо монад, ӯ фавран рафтани худро эълон мекунад;
  • вақте ки ҳамаи бозигарон хориҷ карда мешаванд, бозигари аввал анҷоми бозиро эълон мекунад. Агар ӯ бозиро пештар тарк кунад, пас барои анҷом додани он бозӣ кардан боқӣ мемонад.

Барои ҳалли ин мушкилот, ман DSL-и худро барои равандҳои тиҷоратӣ истифода хоҳам кард, ки ба шумо имкон медиҳад мантиқро дар Котлин бо ҳадди ақали дегхона тасвир кунед.

Дар замимаи app1, раванди тиҷоратии бозигари аввал (вай инчунин ташаббускори бозӣ аст) кор хоҳад кард:

синфи InitialPlayer

import ru.krista.bpm.ProcessInstance
import ru.krista.bpm.runtime.ProcessImpl
import ru.krista.bpm.runtime.constraint.UniqueConstraints
import ru.krista.bpm.runtime.dsl.processModel
import ru.krista.bpm.runtime.dsl.taskOperation
import ru.krista.bpm.runtime.instance.MessageSendInstance

data class PlayerInfo(val name: String, val domain: String, val id: String)

class PlayersList : ArrayList<PlayerInfo>()

// Это класс экземпляра процесса: инкапсулирует его внутреннее состояние
class InitialPlayer : ProcessImpl<InitialPlayer>(initialPlayerModel) {
    var playerName: String by persistent("Player1")
    var energy: Int by persistent(30)
    var players: PlayersList by persistent(PlayersList())
    var shotCounter: Int = 0
}

// Это декларация модели процесса: создается один раз, используется всеми
// экземплярами процесса соответствующего класса
val initialPlayerModel = processModel<InitialPlayer>(name = "InitialPlayer",
                                                     version = 1) {

    // По правилам, первый игрок является инициатором игры и должен быть единственным
    uniqueConstraint = UniqueConstraints.singleton

    // Объявляем активности, из которых состоит бизнес-процесс
    val sendNewGameSignal = signal<String>("NewGame")
    val sendStopGameSignal = signal<String>("StopGame")
    val startTask = humanTask("Start") {
        taskOperation {
            processCondition { players.size > 0 }
            confirmation { "Подключилось ${players.size} игроков. Начинаем?" }
        }
    }
    val stopTask = humanTask("Stop") {
        taskOperation {}
    }
    val waitPlayerJoin = signalWait<String>("PlayerJoin") { signal ->
        players.add(PlayerInfo(
                signal.data!!,
                signal.sender.domain,
                signal.sender.processInstanceId))
        println("... join player ${signal.data} ...")
    }
    val waitPlayerOut = signalWait<String>("PlayerOut") { signal ->
        players.remove(PlayerInfo(
                signal.data!!,
                signal.sender.domain,
                signal.sender.processInstanceId))
        println("... player ${signal.data} is out ...")
    }
    val sendPlayerOut = signal<String>("PlayerOut") {
        signalData = { playerName }
    }
    val sendHandshake = messageSend<String>("Handshake") {
        messageData = { playerName }
        activation = {
            receiverDomain = process.players.last().domain
            receiverProcessInstanceId = process.players.last().id
        }
    }
    val throwStartBall = messageSend<Int>("Ball") {
        messageData = { 1 }
        activation = { selectNextPlayer() }
    }
    val throwBall = messageSend<Int>("Ball") {
        messageData = { shotCounter + 1 }
        activation = { selectNextPlayer() }
        onEntry { energy -= 1 }
    }
    val waitBall = messageWaitData<Int>("Ball") {
        shotCounter = it
    }

    // Теперь конструируем граф процесса из объявленных активностей
    startFrom(sendNewGameSignal)
            .fork("mainFork") {
                next(startTask)
                next(waitPlayerJoin).next(sendHandshake).next(waitPlayerJoin)
                next(waitPlayerOut)
                        .branch("checkPlayers") {
                            ifTrue { players.isEmpty() }
                                    .next(sendStopGameSignal)
                                    .terminate()
                            ifElse().next(waitPlayerOut)
                        }
            }
    startTask.fork("afterStart") {
        next(throwStartBall)
                .branch("mainLoop") {
                    ifTrue { energy < 5 }.next(sendPlayerOut).next(waitBall)
                    ifElse().next(waitBall).next(throwBall).loop()
                }
        next(stopTask).next(sendStopGameSignal)
    }

    // Навешаем на активности дополнительные обработчики для логирования
    sendNewGameSignal.onExit { println("Let's play!") }
    sendStopGameSignal.onExit { println("Stop!") }
    sendPlayerOut.onExit { println("$playerName: I'm out!") }
}

private fun MessageSendInstance<InitialPlayer, Int>.selectNextPlayer() {
    val player = process.players.random()
    receiverDomain = player.domain
    receiverProcessInstanceId = player.id
    println("Step ${process.shotCounter + 1}: " +
            "${process.playerName} >>> ${player.name}")
}

Илова ба иҷрои мантиқи тиҷорат, рамзи дар боло зикршуда метавонад модели объекти раванди бизнесро тавлид кунад, ки онро ҳамчун диаграмма тасвир кардан мумкин аст. Мо то ҳол визуализаторро татбиқ накардаем, аз ин рӯ ба мо лозим омад, ки чанд вақт барои кашидани расмкашӣ сарф кунем (дар ин ҷо ман қайди BPMN-ро дар бораи истифодаи дарвозаҳо барои беҳтар кардани мувофиқати диаграмма бо рамзи дар боло овардашуда каме содда кардам):

Интегратсияи услуби BPM

app2 раванди тиҷоратии бозигари дигарро дар бар мегирад:

синфи RandomPlayer

import ru.krista.bpm.ProcessInstance
import ru.krista.bpm.runtime.ProcessImpl
import ru.krista.bpm.runtime.dsl.processModel
import ru.krista.bpm.runtime.instance.MessageSendInstance

data class PlayerInfo(val name: String, val domain: String, val id: String)

class PlayersList: ArrayList<PlayerInfo>()

class RandomPlayer : ProcessImpl<RandomPlayer>(randomPlayerModel) {

    var playerName: String by input(persistent = true, 
                                    defaultValue = "RandomPlayer")
    var energy: Int by input(persistent = true, defaultValue = 30)
    var players: PlayersList by persistent(PlayersList())
    var allPlayersOut: Boolean by persistent(false)
    var shotCounter: Int = 0

    val selfPlayer: PlayerInfo
        get() = PlayerInfo(playerName, env.eventDispatcher.domainName, id)
}

val randomPlayerModel = processModel<RandomPlayer>(name = "RandomPlayer", 
                                                   version = 1) {

    val waitNewGameSignal = signalWait<String>("NewGame")
    val waitStopGameSignal = signalWait<String>("StopGame")
    val sendPlayerJoin = signal<String>("PlayerJoin") {
        signalData = { playerName }
    }
    val sendPlayerOut = signal<String>("PlayerOut") {
        signalData = { playerName }
    }
    val waitPlayerJoin = signalWaitCustom<String>("PlayerJoin") {
        eventCondition = { signal ->
            signal.sender.processInstanceId != process.id 
                && !process.players.any { signal.sender.processInstanceId == it.id}
        }
        handler = { signal ->
            players.add(PlayerInfo(
                    signal.data!!,
                    signal.sender.domain,
                    signal.sender.processInstanceId))
        }
    }
    val waitPlayerOut = signalWait<String>("PlayerOut") { signal ->
        players.remove(PlayerInfo(
                signal.data!!,
                signal.sender.domain,
                signal.sender.processInstanceId))
        allPlayersOut = players.isEmpty()
    }
    val sendHandshake = messageSend<String>("Handshake") {
        messageData = { playerName }
        activation = {
            receiverDomain = process.players.last().domain
            receiverProcessInstanceId = process.players.last().id
        }
    }
    val receiveHandshake = messageWait<String>("Handshake") { message ->
        if (!players.any { message.sender.processInstanceId == it.id}) {
            players.add(PlayerInfo(
                    message.data!!, 
                    message.sender.domain, 
                    message.sender.processInstanceId))
        }
    }
    val throwBall = messageSend<Int>("Ball") {
        messageData = { shotCounter + 1 }
        activation = { selectNextPlayer() }
        onEntry { energy -= 1 }
    }
    val waitBall = messageWaitData<Int>("Ball") {
        shotCounter = it
    }

    startFrom(waitNewGameSignal)
            .fork("mainFork") {
                next(sendPlayerJoin)
                        .branch("mainLoop") {
                            ifTrue { energy < 5 || allPlayersOut }
                                    .next(sendPlayerOut)
                                    .next(waitBall)
                            ifElse()
                                    .next(waitBall)
                                    .next(throwBall)
                                    .loop()
                        }
                next(waitPlayerJoin).next(sendHandshake).next(waitPlayerJoin)
                next(waitPlayerOut).next(waitPlayerOut)
                next(receiveHandshake).next(receiveHandshake)
                next(waitStopGameSignal).terminate()
            }

    sendPlayerJoin.onExit { println("$playerName: I'm here!") }
    sendPlayerOut.onExit { println("$playerName: I'm out!") }
}

private fun MessageSendInstance<RandomPlayer, Int>.selectNextPlayer() {
    val player = if (process.players.isNotEmpty()) 
        process.players.random() 
    else 
        process.selfPlayer
    receiverDomain = player.domain
    receiverProcessInstanceId = player.id
    println("Step ${process.shotCounter + 1}: " +
            "${process.playerName} >>> ${player.name}")
}

Диаграмма:

Интегратсияи услуби BPM

Дар замимаи app3, мо плеерро бо рафтори каме дигар месозем: ба ҷои интихоби тасодуфии бозигари навбатӣ, ӯ мувофиқи алгоритми даврӣ амал мекунад:

синфи RoundRobinPlayer

import ru.krista.bpm.ProcessInstance
import ru.krista.bpm.runtime.ProcessImpl
import ru.krista.bpm.runtime.dsl.processModel
import ru.krista.bpm.runtime.instance.MessageSendInstance

data class PlayerInfo(val name: String, val domain: String, val id: String)

class PlayersList: ArrayList<PlayerInfo>()

class RoundRobinPlayer : ProcessImpl<RoundRobinPlayer>(roundRobinPlayerModel) {

    var playerName: String by input(persistent = true, 
                                    defaultValue = "RoundRobinPlayer")
    var energy: Int by input(persistent = true, defaultValue = 30)
    var players: PlayersList by persistent(PlayersList())
    var nextPlayerIndex: Int by persistent(-1)
    var allPlayersOut: Boolean by persistent(false)
    var shotCounter: Int = 0

    val selfPlayer: PlayerInfo
        get() = PlayerInfo(playerName, env.eventDispatcher.domainName, id)
}

val roundRobinPlayerModel = processModel<RoundRobinPlayer>(
        name = "RoundRobinPlayer", 
        version = 1) {

    val waitNewGameSignal = signalWait<String>("NewGame")
    val waitStopGameSignal = signalWait<String>("StopGame")
    val sendPlayerJoin = signal<String>("PlayerJoin") {
        signalData = { playerName }
    }
    val sendPlayerOut = signal<String>("PlayerOut") {
        signalData = { playerName }
    }
    val waitPlayerJoin = signalWaitCustom<String>("PlayerJoin") {
        eventCondition = { signal ->
            signal.sender.processInstanceId != process.id 
                && !process.players.any { signal.sender.processInstanceId == it.id}
        }
        handler = { signal ->
            players.add(PlayerInfo(
                    signal.data!!, 
                    signal.sender.domain, 
                    signal.sender.processInstanceId))
        }
    }
    val waitPlayerOut = signalWait<String>("PlayerOut") { signal ->
        players.remove(PlayerInfo(
                signal.data!!, 
                signal.sender.domain, 
                signal.sender.processInstanceId))
        allPlayersOut = players.isEmpty()
    }
    val sendHandshake = messageSend<String>("Handshake") {
        messageData = { playerName }
        activation = {
            receiverDomain = process.players.last().domain
            receiverProcessInstanceId = process.players.last().id
        }
    }
    val receiveHandshake = messageWait<String>("Handshake") { message ->
        if (!players.any { message.sender.processInstanceId == it.id}) {
            players.add(PlayerInfo(
                    message.data!!, 
                    message.sender.domain, 
                    message.sender.processInstanceId))
        }
    }
    val throwBall = messageSend<Int>("Ball") {
        messageData = { shotCounter + 1 }
        activation = { selectNextPlayer() }
        onEntry { energy -= 1 }
    }
    val waitBall = messageWaitData<Int>("Ball") {
        shotCounter = it
    }

    startFrom(waitNewGameSignal)
            .fork("mainFork") {
                next(sendPlayerJoin)
                        .branch("mainLoop") {
                            ifTrue { energy < 5 || allPlayersOut }
                                    .next(sendPlayerOut)
                                    .next(waitBall)
                            ifElse()
                                    .next(waitBall)
                                    .next(throwBall)
                                    .loop()
                        }
                next(waitPlayerJoin).next(sendHandshake).next(waitPlayerJoin)
                next(waitPlayerOut).next(waitPlayerOut)
                next(receiveHandshake).next(receiveHandshake)
                next(waitStopGameSignal).terminate()
            }

    sendPlayerJoin.onExit { println("$playerName: I'm here!") }
    sendPlayerOut.onExit { println("$playerName: I'm out!") }
}

private fun MessageSendInstance<RoundRobinPlayer, Int>.selectNextPlayer() {
    var idx = process.nextPlayerIndex + 1
    if (idx >= process.players.size) {
        idx = 0
    }
    process.nextPlayerIndex = idx
    val player = if (process.players.isNotEmpty()) 
        process.players[idx] 
    else 
        process.selfPlayer
    receiverDomain = player.domain
    receiverProcessInstanceId = player.id
    println("Step ${process.shotCounter + 1}: " +
            "${process.playerName} >>> ${player.name}")
}

Дар акси ҳол, рафтори бозигар аз рафтори қаблӣ фарқ намекунад, бинобар ин диаграмма тағир намеёбад.

Ҳоло ба мо озмоиш лозим аст, то ҳамаашро иҷро кунем. Ман танҳо рамзи худи санҷишро медиҳам, то мақоларо бо таблиғ печида нашавам (воқеан, ман муҳити санҷиширо барои санҷиши ҳамгироии дигар равандҳои тиҷорат истифода кардам):

testGame ()

@Test
public void testGame() throws InterruptedException {
    String pl2 = startProcess(app2, "RandomPlayer", playerParams("Player2", 20));
    String pl3 = startProcess(app2, "RandomPlayer", playerParams("Player3", 40));
    String pl4 = startProcess(app3, "RoundRobinPlayer", playerParams("Player4", 25));
    String pl5 = startProcess(app3, "RoundRobinPlayer", playerParams("Player5", 35));
    String pl1 = startProcess(app1, "InitialPlayer");
    // Теперь нужно немного подождать, пока игроки "познакомятся" друг с другом.
    // Ждать через sleep - плохое решение, зато самое простое. 
    // Не делайте так в серьезных тестах!
    Thread.sleep(1000);
    // Запускаем игру, закрывая пользовательскую активность
    assertTrue(closeTask(app1, pl1, "Start"));
    app1.getWaiting().waitProcessFinished(pl1);
    app2.getWaiting().waitProcessFinished(pl2);
    app2.getWaiting().waitProcessFinished(pl3);
    app3.getWaiting().waitProcessFinished(pl4);
    app3.getWaiting().waitProcessFinished(pl5);
}

private Map<String, Object> playerParams(String name, int energy) {
    Map<String, Object> params = new HashMap<>();
    params.put("playerName", name);
    params.put("energy", energy);
    return params;
}

Санҷишро иҷро кунед, ба гузориш нигаред:

баромади консол

Взята блокировка ключа lock://app1/process/InitialPlayer
Let's play!
Снята блокировка ключа lock://app1/process/InitialPlayer
Player2: I'm here!
Player3: I'm here!
Player4: I'm here!
Player5: I'm here!
... join player Player2 ...
... join player Player4 ...
... join player Player3 ...
... join player Player5 ...
Step 1: Player1 >>> Player3
Step 2: Player3 >>> Player5
Step 3: Player5 >>> Player3
Step 4: Player3 >>> Player4
Step 5: Player4 >>> Player3
Step 6: Player3 >>> Player4
Step 7: Player4 >>> Player5
Step 8: Player5 >>> Player2
Step 9: Player2 >>> Player5
Step 10: Player5 >>> Player4
Step 11: Player4 >>> Player2
Step 12: Player2 >>> Player4
Step 13: Player4 >>> Player1
Step 14: Player1 >>> Player4
Step 15: Player4 >>> Player3
Step 16: Player3 >>> Player1
Step 17: Player1 >>> Player2
Step 18: Player2 >>> Player3
Step 19: Player3 >>> Player1
Step 20: Player1 >>> Player5
Step 21: Player5 >>> Player1
Step 22: Player1 >>> Player2
Step 23: Player2 >>> Player4
Step 24: Player4 >>> Player5
Step 25: Player5 >>> Player3
Step 26: Player3 >>> Player4
Step 27: Player4 >>> Player2
Step 28: Player2 >>> Player5
Step 29: Player5 >>> Player2
Step 30: Player2 >>> Player1
Step 31: Player1 >>> Player3
Step 32: Player3 >>> Player4
Step 33: Player4 >>> Player1
Step 34: Player1 >>> Player3
Step 35: Player3 >>> Player4
Step 36: Player4 >>> Player3
Step 37: Player3 >>> Player2
Step 38: Player2 >>> Player5
Step 39: Player5 >>> Player4
Step 40: Player4 >>> Player5
Step 41: Player5 >>> Player1
Step 42: Player1 >>> Player5
Step 43: Player5 >>> Player3
Step 44: Player3 >>> Player5
Step 45: Player5 >>> Player2
Step 46: Player2 >>> Player3
Step 47: Player3 >>> Player2
Step 48: Player2 >>> Player5
Step 49: Player5 >>> Player4
Step 50: Player4 >>> Player2
Step 51: Player2 >>> Player5
Step 52: Player5 >>> Player1
Step 53: Player1 >>> Player5
Step 54: Player5 >>> Player3
Step 55: Player3 >>> Player5
Step 56: Player5 >>> Player2
Step 57: Player2 >>> Player1
Step 58: Player1 >>> Player4
Step 59: Player4 >>> Player1
Step 60: Player1 >>> Player4
Step 61: Player4 >>> Player3
Step 62: Player3 >>> Player2
Step 63: Player2 >>> Player5
Step 64: Player5 >>> Player4
Step 65: Player4 >>> Player5
Step 66: Player5 >>> Player1
Step 67: Player1 >>> Player5
Step 68: Player5 >>> Player3
Step 69: Player3 >>> Player4
Step 70: Player4 >>> Player2
Step 71: Player2 >>> Player5
Step 72: Player5 >>> Player2
Step 73: Player2 >>> Player1
Step 74: Player1 >>> Player4
Step 75: Player4 >>> Player1
Step 76: Player1 >>> Player2
Step 77: Player2 >>> Player5
Step 78: Player5 >>> Player4
Step 79: Player4 >>> Player3
Step 80: Player3 >>> Player1
Step 81: Player1 >>> Player5
Step 82: Player5 >>> Player1
Step 83: Player1 >>> Player4
Step 84: Player4 >>> Player5
Step 85: Player5 >>> Player3
Step 86: Player3 >>> Player5
Step 87: Player5 >>> Player2
Step 88: Player2 >>> Player3
Player2: I'm out!
Step 89: Player3 >>> Player4
... player Player2 is out ...
Step 90: Player4 >>> Player1
Step 91: Player1 >>> Player3
Step 92: Player3 >>> Player1
Step 93: Player1 >>> Player4
Step 94: Player4 >>> Player3
Step 95: Player3 >>> Player5
Step 96: Player5 >>> Player1
Step 97: Player1 >>> Player5
Step 98: Player5 >>> Player3
Step 99: Player3 >>> Player5
Step 100: Player5 >>> Player4
Step 101: Player4 >>> Player5
Player4: I'm out!
... player Player4 is out ...
Step 102: Player5 >>> Player1
Step 103: Player1 >>> Player3
Step 104: Player3 >>> Player1
Step 105: Player1 >>> Player3
Step 106: Player3 >>> Player5
Step 107: Player5 >>> Player3
Step 108: Player3 >>> Player1
Step 109: Player1 >>> Player3
Step 110: Player3 >>> Player5
Step 111: Player5 >>> Player1
Step 112: Player1 >>> Player3
Step 113: Player3 >>> Player5
Step 114: Player5 >>> Player3
Step 115: Player3 >>> Player1
Step 116: Player1 >>> Player3
Step 117: Player3 >>> Player5
Step 118: Player5 >>> Player1
Step 119: Player1 >>> Player3
Step 120: Player3 >>> Player5
Step 121: Player5 >>> Player3
Player5: I'm out!
... player Player5 is out ...
Step 122: Player3 >>> Player5
Step 123: Player5 >>> Player1
Player5: I'm out!
Step 124: Player1 >>> Player3
... player Player5 is out ...
Step 125: Player3 >>> Player1
Step 126: Player1 >>> Player3
Player1: I'm out!
... player Player1 is out ...
Step 127: Player3 >>> Player3
Player3: I'm out!
Step 128: Player3 >>> Player3
... player Player3 is out ...
Player3: I'm out!
Stop!
Step 129: Player3 >>> Player3
Player3: I'm out!

Аз ин ҳама як қатор хулосаҳои муҳим баровардан мумкин аст:

  • агар асбобҳои зарурӣ мавҷуд бошанд, таҳиягарони барнома метавонанд бидуни ҷудо шудан аз мантиқи тиҷорӣ робитаҳои ҳамгироиро байни барномаҳо эҷод кунанд;
  • мураккабии (мураккабӣ) вазифаи ҳамгироӣ, ки салоҳиятҳои муҳандисиро талаб мекунад, метавонад дар дохили чаҳорчӯба пинҳон карда шавад, агар он дар аввал дар меъмории чаҳорчӯба гузошта шуда бошад. Мушкилии вазифаро (мушкилот) пинҳон кардан мумкин нест, бинобар ин ҳалли вазифаи душвор дар код мувофиқан ба назар мерасад;
  • Ҳангоми таҳияи мантиқи ҳамгироӣ дар ниҳоят мувофиқат ва набудани хаттӣ будани тағирёбии ҳолати ҳамаи иштирокчиёни интегратсияро ба назар гирифтан лозим аст. Ин моро водор мекунад, ки мантиқро мураккаб созем, то он ба тартиби рӯй додани ҳодисаҳои беруна ҳассос гардад. Дар мисоли мо, бозигар пас аз эълони аз бозӣ баромаданаш маҷбур аст, ки дар бозӣ иштирок кунад: бозигарони дигар тӯбро ба ӯ идома медиҳанд, то он даме, ки маълумот дар бораи баромаданаш аз ҷониби ҳамаи иштирокчиён коркард карда шавад. Ин мантиқ аз қоидаҳои бозӣ пайравӣ намекунад ва дар доираи меъмории интихобшуда ҳалли созиш аст.

Баъд, биёед дар бораи нозукиҳои гуногуни ҳалли мо, созишҳо ва дигар нуктаҳо сӯҳбат кунем.

Ҳама паёмҳо дар як навбат

Ҳама замимаҳои ҳамгирошуда бо як автобуси ҳамгироӣ кор мекунанд, ки он ҳамчун брокери беруна пешниҳод карда мешавад, як BPMQueue барои паёмҳо ва як мавзӯи BPMTopic барои сигналҳо (ҳодисаҳо). Гузаронидани ҳама паёмҳо тавассути як навбат худ як созиш аст. Дар сатњи мантиќи тиљоратї, шумо акнун метавонед бе ворид намудани таѓйирот ба сохтори система њар ќадар навъњои нави паёмњоро, ки хоњед, ворид кунед. Ин соддагардонии назаррас аст, аммо он хатарҳои муайяне дорад, ки дар заминаи вазифаҳои маъмулии мо, ба назари мо он қадар муҳим набуд.

Интегратсияи услуби BPM

Аммо, дар ин ҷо як нозуки вуҷуд дорад: ҳар як барнома паёмҳои "худро" аз навбат дар даромадгоҳ бо номи домени худ филтр мекунад. Инчунин, доменро дар сигналҳо муайян кардан мумкин аст, агар ба шумо лозим аст, ки "миқёси" сигналро бо як барнома маҳдуд кунед. Ин бояд фарохмаҷрои автобусро зиёд кунад, аммо мантиқи тиҷорӣ бояд ҳоло бо номҳои домейнҳо кор кунад: ҳатмӣ барои ирсоли паёмҳо, матлуб барои сигналҳо.

Таъмини эътимоднокии автобуси ҳамгироӣ

Эътимод аз якчанд чиз иборат аст:

  • Брокери паёми интихобшуда ҷузъи муҳими меъморӣ ва як нуқтаи нокомӣ мебошад: он бояд ба таври кофӣ ба хато таҳаммулпазир бошад. Шумо бояд танҳо амалияҳои санҷидашудаи вақтро бо дастгирии хуб ва ҷомеаи калон истифода баред;
  • дастрасии баланди брокери паёмиро таъмин кардан лозим аст, ки барои он он бояд аз замимаҳои интегралӣ ҷудо карда шавад (мавҷудияти баланди замимаҳо бо мантиқи тиҷорӣ хеле мушкилтар ва гаронарзиштар аст, ки таъмин намояд);
  • брокер вазифадор аст, ки кафолати интиқолро "ҳадди ақал як маротиба" пешниҳод кунад. Ин талаботи ҳатмӣ барои кори боэътимоди автобуси ҳамгироӣ мебошад. Кафолатҳои сатҳи "дақиқ як маротиба" лозим нест: равандҳои тиҷоратӣ одатан ба воридшавии такрории паёмҳо ё рӯйдодҳо ҳассос нестанд ва дар вазифаҳои махсус, ки ин муҳим аст, илова кардани чекҳои иловагӣ ба мантиқи тиҷорат нисбат ба истифодаи доимӣ осонтар аст. ба ҷои "гарон" " кафолатҳо;
  • фиристодани паёмҳо ва сигналҳо бояд дар амалиёти умумӣ бо тағир додани ҳолати равандҳои тиҷоратӣ ва маълумоти домен ҷалб карда шаванд. Варианти афзалиятнок истифодаи намуна аст Қуттии содиротии транзаксия, аммо он ҷадвали иловагӣ дар базаи маълумот ва реле талаб мекунад. Дар замимаҳои JEE, онро бо истифода аз менеҷери маҳаллии JTA содда кардан мумкин аст, аммо пайвастшавӣ ба брокери интихобшуда бояд дар реҷа кор кунад XA;
  • коркардкунандагони паёмҳо ва рӯйдодҳои воридотӣ бояд инчунин бо амалиёти тағир додани ҳолати раванди корӣ кор кунанд: агар чунин транзаксия баргардонида шавад, пас гирифтани паём низ бояд бекор карда шавад;
  • паёмҳое, ки аз сабаби хатогиҳо расонида намешаванд, бояд дар мағозаи алоҳида нигоҳ дошта шаванд D.L.Q. (Навбати мактубҳои мурда). Барои ин, мо як микросервиси платформаи алоҳидаеро таъсис додем, ки чунин паёмҳоро дар нигаҳдории худ нигоҳ медорад, онҳоро аз рӯи атрибутҳо (барои гурӯҳбандӣ ва ҷустуҷӯи зуд) индексатсия мекунад ва API-ро барои дидан, фиристодан ба суроғаи таъинот ва нест кардани паёмҳо фош мекунад. Маъмурони система метавонанд бо ин хидмат тавассути интерфейси веби худ кор кунанд;
  • дар танзимоти брокер, шумо бояд шумораи такрории интиқол ва таъхирҳои интиқолро танзим кунед, то эҳтимолияти ворид шудани паёмҳо ба DLQ (ҳисоб кардани параметрҳои оптималӣ қариб ғайриимкон аст, аммо шумо метавонед ба таври таҷрибавӣ амал кунед ва онҳоро дар давоми интиқол танзим кунед. амалиёт);
  • мағозаи DLQ бояд пайваста назорат карда шавад ва системаи мониторинг бояд маъмурони системаро огоҳ созад, то онҳо ҳангоми пайдо шудани паёмҳои ирсолнашуда ҳарчи зудтар посух диҳанд. Ин "минтақаи зарар" -и нокомӣ ё хатои мантиқии тиҷоратро коҳиш медиҳад;
  • автобуси ҳамгироӣ бояд ба набудани муваққатии барномаҳо ҳассос набошад: обунаҳои мавзӯъ бояд пойдор бошанд ва номи домени барнома бояд беназир бошад, то ягон каси дигар кӯшиш накунад, ки паёми худро аз навбат ҳангоми набудани барнома коркард кунад.

Таъмини бехатарии риштаи мантиқи тиҷорат

Як мисоли раванди бизнес метавонад якбора якчанд паём ва рӯйдодҳоро қабул кунад, ки коркарди онҳо дар баробари оғоз меёбад. Ҳамзамон, барои таҳиягари барнома ҳама чиз бояд оддӣ ва бехатар бошад.

Раванди мантиқи тиҷорат ҳар як ҳодисаи берунаро, ки ба ин раванди тиҷорат таъсир мерасонад, коркард мекунад. Ин рӯйдодҳо метавонанд:

  • оғози раванди бизнес;
  • амали корбар вобаста ба фаъолият дар дохили раванди тиҷорат;
  • гирифтани паём ё сигнал, ки ба он инстансияи равандҳои тиҷоратӣ обуна шудааст;
  • ба охир расидани таймер, ки инстансияи равандҳои корӣ муқаррар кардааст;
  • назорати амал тавассути API (масалан, қатъ кардани раванд).

Ҳар як чунин ҳодиса метавонад ҳолати як мисоли раванди тиҷоратиро тағир диҳад: баъзе фаъолиятҳо метавонанд ба охир расад ва дигарон оғоз шаванд, арзишҳои хосиятҳои доимӣ метавонанд тағир ёбанд. Пӯшидани ҳама гуна фаъолият метавонад боиси фаъол шудани як ё якчанд фаъолиятҳои зерин гардад. Онҳо, дар навбати худ, метавонанд интизории рӯйдодҳои дигарро бас кунанд ё агар ба онҳо ягон маълумоти иловагӣ эҳтиёҷ надошта бошанд, онҳо метавонанд дар ҳамон транзаксия анҷом диҳанд. Пеш аз бастани транзаксия, ҳолати нави раванди тиҷорат дар пойгоҳи додаҳо нигоҳ дошта мешавад, ки дар он ҷо ҳодисаи навбатии беруна интизор мешавад.

Маълумоти доимии равандҳои тиҷорӣ, ки дар пойгоҳи додаҳои релятсионӣ нигоҳ дошта мешаванд, нуқтаи хеле қулайи ҳамоҳангсозии коркард ҳангоми истифодаи SELECT FOR UPDATE мебошад. Агар як транзаксия муяссар шуд, ки ҳолати раванди тиҷоратиро аз база барои тағир додани он ба даст орад, пас ҳеҷ як амалиёти дигари мувозӣ наметавонад ҳамон ҳолатро барои тағирёбии дигар ба даст орад ва пас аз анҷоми муомилоти аввал, дуюм кафолат дода мешавад, ки ҳолати аллакай тағирёфтаро қабул кунад.

Бо истифода аз қуфлҳои пессимистӣ дар тарафи DBMS, мо ҳама талаботҳои заруриро иҷро мекунем Кислота, ва инчунин қобилияти васеъ кардани барномаи мантиқии тиҷорӣ тавассути зиёд кардани шумораи мисолҳои иҷрошавандаро нигоҳ доред.

Бо вуҷуди ин, қуфлҳои пессимистӣ моро бо бунбастҳо таҳдид мекунанд, ки ин маънои онро дорад, ки SELECT FOR UPDATE бояд то ҳол бо баъзе танаффусҳои оқилона дар ҳолати бунбаст дар баъзе ҳолатҳои даҳшатнок дар мантиқи тиҷорат маҳдуд карда шавад.

Мушкилоти дигар ин синхронизатсияи оғози раванди бизнес мебошад. Дар ҳоле ки ягон мисоли равандҳои корӣ вуҷуд надорад, дар пойгоҳи додаҳо низ ҳолат вуҷуд надорад, аз ин рӯ усули тавсифшуда кор намекунад. Агар шумо хоҳед, ки беназирии як мисоли раванди бизнесро дар доираи мушаххас таъмин кунед, пас ба шумо як намуди объекти ҳамоҳангсозӣ, ки бо синфи раванд ва доираи мувофиқ алоқаманд аст, лозим аст. Барои ҳалли ин мушкилот, мо механизми дигари қулфкуниро истифода мебарем, ки ба мо имкон медиҳад, ки ба манбаи худсарона, ки тавассути калид дар формати URI муайян шудааст, тавассути хидмати беруна қулф гирем.

Дар мисолҳои мо, раванди тиҷорати InitialPlayer дорои эъломия мебошад

uniqueConstraint = UniqueConstraints.singleton

Аз ин рӯ, журнал дорои паёмҳо дар бораи гирифтан ва озод кардани қулфи калиди мувофиқ мебошад. Барои дигар равандҳои тиҷоратӣ чунин паёмҳо вуҷуд надоранд: uniqueConstraint муқаррар карда нашудааст.

Проблемаҳои раванди тиҷорат бо ҳолати доимӣ

Баъзан доштани ҳолати доимӣ на танҳо кӯмак мекунад, балки воқеан ба рушд халал мерасонад.
Мушкилот вақте оғоз мешавад, ки ба шумо лозим аст, ки ба мантиқи тиҷорат ва/ё модели равандҳои корӣ тағирот ворид кунед. Ҳеҷ гуна тағирот ба ҳолати кӯҳнаи равандҳои тиҷорат мувофиқат намекунад. Агар дар базаи маълумот бисёр мисолҳои "зинда" вуҷуд дошта бошанд, пас ворид кардани тағиротҳои номувофиқ метавонад боиси мушкилоти зиёд гардад, ки мо аксар вақт ҳангоми истифодаи jBPM дучор мешавем.

Вобаста аз умқи тағирот, шумо метавонед бо ду роҳ амал кунед:

  1. намуди нави равандҳои тиҷорӣ эҷод кунед, то ба чизи кӯҳна тағироти номувофиқ ворид накунад ва ҳангоми оғоз кардани мисолҳои нав онро ба ҷои пешина истифода баред. Ҳолатҳои кӯҳна кор карданро "тарзи кӯҳна" идома медиҳанд;
  2. интиқол додани ҳолати доимии равандҳои бизнес ҳангоми навсозии мантиқи тиҷорат.

Роҳи аввал соддатар аст, аммо маҳдудиятҳо ва нуқсонҳои худро дорад, масалан:

  • такрори мантиқи тиҷорат дар бисёре аз моделҳои равандҳои бизнес, афзоиши ҳаҷми мантиқи тиҷорат;
  • аксар вақт гузариши фаврӣ ба мантиқи нави тиҷорат талаб карда мешавад (қариб ҳамеша дар робита ба вазифаҳои ҳамгироӣ);
  • таҳиякунанда намедонад, ки дар кадом лаҳза моделҳои кӯҳнаро нест кардан мумкин аст.

Дар амал, мо ҳарду равишро истифода мебарем, аммо барои содда кардани ҳаёти худ як қатор қарорҳо қабул кардем:

  • дар пойгоҳи додаҳо, ҳолати доимии раванди тиҷорат дар шакли ба осонӣ хондашаванда ва коркардшаванда нигоҳ дошта мешавад: дар сатри формати JSON. Ин ба шумо имкон медиҳад, ки муҳоҷиратро ҳам дар дохили барнома ва ҳам берун аз он анҷом диҳед. Дар ҳолатҳои шадид, шумо инчунин метавонед онро бо дастакҳо таҳрир кунед (махсусан дар таҳия ҳангоми ислоҳкунӣ муфид аст);
  • мантиқи тиҷорати ҳамгироӣ номҳои равандҳои бизнесро истифода намебарад, то дар ҳар вақт имконпазир бошад, ки амалисозии яке аз равандҳои иштироккунанда бо номи нав, бо номи нав иваз карда шавад (масалан, "InitialPlayerV2"). Пайвастшавӣ тавассути номҳои паёмҳо ва сигналҳо ба амал меояд;
  • модели раванд рақами версия дорад, ки агар мо ба ин модел тағйироти номувофиқ ворид кунем, онро афзоиш медиҳем ва ин рақам дар баробари ҳолати мисоли раванд нигоҳ дошта мешавад;
  • ҳолати доимии раванд аз база аввал ба модели объекти қулай хонда мешавад, ки тартиби муҳоҷират метавонад бо он кор кунад, агар рақами версияи модел тағир ёбад;
  • тартиби муњољират дар пањлўи мантиќи тиљоратї љойгир карда мешавад ва барои њар як мисоли раванди бизнес њангоми барќарор кардани он аз базаи маълумот "танбал" номида мешавад;
  • агар ба шумо лозим ояд, ки ҳолати ҳамаи инстансияҳои равандро зуд ва синхронӣ интиқол диҳед, ҳалли бештари классикии интиқоли пойгоҳи додаҳо истифода мешавад, аммо шумо бояд дар он ҷо бо JSON кор кунед.

Оё ба ман чаҳорчӯбаи дигар барои равандҳои тиҷорат лозим аст?

Қарорҳои дар мақола тавсифшуда ба мо имкон доданд, ки ҳаёти худро ба таври назаррас содда гардонем, доираи масъалаҳои ҳалшавандаро дар сатҳи таҳияи барномаҳо васеъ кунем ва ғояи ҷудо кардани мантиқи бизнесро ба хидматрасониҳои хурд ҷолибтар созем. Барои ин кори зиёде анҷом дода шуд, як чаҳорчӯбаи хеле «сабук» барои равандҳои бизнес, инчунин ҷузъҳои хидматрасонӣ барои ҳалли мушкилоти муайяншуда дар доираи доираи васеи вазифаҳои амалӣ таъсис дода шуданд. Мо хоҳиш дорем, ки ин натиҷаҳоро мубодила кунем, таҳияи ҷузъҳои умумиро ба дастрасии кушод дар зери иҷозатномаи ройгон расонем. Ин каме кӯшиш ва вақтро талаб мекунад. Фаҳмидани талабот ба чунин қарорҳо метавонад барои мо ҳавасмандии иловагӣ бошад. Дар мақолаи пешниҳодшуда ба имкониятҳои худи чаҳорчӯба аҳамияти хеле кам дода мешавад, аммо баъзеи онҳо аз мисолҳои овардашуда дида мешаванд. Агар мо ба ҳар ҳол чаҳорчӯбаи худро нашр кунем, мақолаи алоҳида ба он бахшида мешавад. Дар ҳамин ҳол, мо миннатдор хоҳем буд, агар шумо бо посух ба ин савол каме фикру мулоҳиза гузоред:

Танҳо корбарони сабтиномшуда метавонанд дар пурсиш иштирок кунанд. даромад, Лутфан.

Оё ба ман чаҳорчӯбаи дигар барои равандҳои тиҷорат лозим аст?

  • 18,8%Бале, ман кайхо боз чунин чизеро мечустам.

  • 12,5%омӯхтани бештар дар бораи татбиқи шумо ҷолиб аст, он метавонад муфид бошад2

  • 6,2%мо яке аз чорчубахои мавчударо истифода мебарем, вале мо дар бораи иваз кардани он фикр мекунем

  • 18,8%мо яке аз чаҳорчӯбаҳои мавҷударо истифода мебарем, ҳама чиз мувофиқ аст3

  • 18,8%мубориза бе чаҳорчӯба3

  • 25,0%худро нависед4

16 корбар овоз доданд. 7 корбар худдорӣ карданд.

Манбаъ: will.com

Илова Эзоҳ