Integrazzjoni stil BPM

Integrazzjoni stil BPM

Hi Habr!

Kumpanija tagħna tispeċjalizza fl-iżvilupp ta 'soluzzjonijiet ta' softwer tal-klassi ERP, li fihom l-akbar sehem huwa okkupat minn sistemi transazzjonali b'ammont kbir ta 'loġika tan-negozju u fluss tax-xogħol a la EDMS. Verżjonijiet moderni tal-prodotti tagħna huma bbażati fuq teknoloġiji JavaEE, iżda aħna wkoll qed nesperimentaw b'mod attiv bil-mikroservizzi. Wieħed mill-oqsma l-aktar problematiċi ta 'soluzzjonijiet bħal dawn huwa l-integrazzjoni ta' sottosistemi varji relatati ma 'oqsma li jmissu magħhom. Il-kompiti ta 'integrazzjoni dejjem tawna uġigħ ta' ras kbir, irrispettivament mill-istili arkitettoniċi, munzelli ta 'teknoloġija u oqfsa li nużaw, iżda reċentement kien hemm progress biex insolvu problemi bħal dawn.

Fl-artiklu miġjub għall-attenzjoni tiegħek, ser nitkellem dwar l-esperjenza u r-riċerka arkitettonika ta 'NPO Krista fiż-żona magħżula. Se nikkunsidraw ukoll eżempju ta’ soluzzjoni sempliċi għal problema ta’ integrazzjoni mil-lat ta’ żviluppatur ta’ applikazzjoni u nsiru naħbu x’inhu moħbi wara din is-sempliċità.

Ċaħda

Is-soluzzjonijiet arkitettoniċi u tekniċi deskritti fl-artiklu huma offruti minni bbażati fuq esperjenza personali fil-kuntest ta 'kompiti speċifiċi. Dawn is-soluzzjonijiet ma jippretendux li huma universali u jistgħu ma jkunux ottimali taħt kundizzjonijiet oħra ta 'użu.

X'għandu x'jaqsam miegħu l-BPM?

Biex inwieġbu din il-mistoqsija, għandna bżonn nidħlu ftit fl-ispeċifiċitajiet tal-problemi applikati tas-soluzzjonijiet tagħna. Il-parti ewlenija tal-loġika tan-negozju fis-sistema transazzjonali tipika tagħna hija d-dħul tad-dejta fid-database permezz ta 'interfaces tal-utent, verifika manwali u awtomatizzata ta' din id-dejta, tgħaddiha minn xi fluss tax-xogħol, tippubblikaha għal sistema oħra / database analitika / arkivju, li tiġġenera rapporti. Għalhekk, il-funzjoni ewlenija tas-sistema għall-klijenti hija l-awtomazzjoni tal-proċessi tan-negozju interni tagħhom.

Għall-konvenjenza, nużaw it-terminu "dokument" fil-komunikazzjoni bħala xi astrazzjoni ta 'sett ta' dejta, magħquda minn ċavetta komuni, li magħha jista 'jiġi "mehmuż" fluss tax-xogħol speċifiku.
Imma xi ngħidu dwar il-loġika tal-integrazzjoni? Wara kollox, il-kompitu ta 'integrazzjoni huwa ġġenerat mill-arkitettura tas-sistema, li hija "serrat" f'partijiet MHUX fuq talba tal-klijent, iżda taħt l-influwenza ta' fatturi kompletament differenti:

  • taħt l-influwenza tal-liġi ta 'Conway;
  • bħala riżultat tal-użu mill-ġdid ta' sottosistemi żviluppati qabel għal prodotti oħra;
  • kif deċiż mill-perit, ibbażat fuq rekwiżiti mhux funzjonali.

Hemm tentazzjoni kbira li tissepara l-loġika tal-integrazzjoni mill-loġika tan-negozju tal-fluss tax-xogħol ewlieni sabiex ma tniġġesx il-loġika tan-negozju b'artifacts tal-integrazzjoni u tiffranka lill-iżviluppatur tal-applikazzjoni milli jkollu jidħol fil-partikolaritajiet tal-pajsaġġ arkitettoniku tas-sistema. Dan l-approċċ għandu numru ta 'vantaġġi, iżda l-prattika turi l-ineffiċjenza tagħha:

  • is-soluzzjoni ta 'problemi ta' integrazzjoni ġeneralment tiżżerżaq sa l-aktar għażliet sempliċi fil-forma ta 'sejħiet sinkroniċi minħabba l-punti ta' estensjoni limitati fl-implimentazzjoni tal-fluss tax-xogħol prinċipali (aktar dwar in-nuqqasijiet ta 'integrazzjoni sinkronika hawn taħt);
  • artifacts ta 'integrazzjoni għadhom jippenetraw il-loġika tan-negozju prinċipali meta jkun meħtieġ feedback minn sottosistema oħra;
  • l-iżviluppatur tal-applikazzjoni jinjora l-integrazzjoni u jista 'faċilment ikisserha billi jibdel il-fluss tax-xogħol;
  • is-sistema ma tibqax waħda sħiħa mill-perspettiva tal-utent, "ħjatat" bejn is-sottosistemi jsiru notevoli, operazzjonijiet tal-utent żejda jidhru li jibdew it-trasferiment tad-data minn subsistema għal oħra.

Approċċ ieħor huwa li jitqiesu l-interazzjonijiet ta 'integrazzjoni bħala parti integrali tal-loġika tan-negozju ewlieni u l-fluss tax-xogħol. Biex iżżomm ir-rekwiżiti tal-ħiliet tal-iżviluppaturi tal-applikazzjonijiet milli jogħlew, il-ħolqien ta 'interazzjonijiet ġodda ta' integrazzjoni għandu jsir faċilment u b'mod naturali, b'għażliet minimi għall-għażla ta 'soluzzjoni. Dan huwa aktar diffiċli milli jidher: l-għodda għandha tkun b'saħħitha biżżejjed biex tipprovdi lill-utent bil-varjetà meħtieġa ta 'għażliet għall-użu tagħha u fl-istess ħin ma tħallix lilhom infushom li jiġu sparati fis-sieq. Hemm ħafna mistoqsijiet li inġinier għandu jwieġeb fil-kuntest tal-kompiti ta 'integrazzjoni, iżda li żviluppatur ta' applikazzjoni m'għandux jaħseb dwarhom fix-xogħol ta 'kuljum tiegħu: konfini tat-tranżazzjonijiet, konsistenza, atomiċità, sigurtà, skalar, distribuzzjoni ta' tagħbija u riżorsi, routing, marshaling, kuntesti ta' propagazzjoni u taqleb, eċċ. Huwa meħtieġ li l-iżviluppaturi tal-applikazzjonijiet jiġu offruti mudelli ta' deċiżjonijiet pjuttost sempliċi, li fihom it-tweġibiet għall-mistoqsijiet kollha bħal dawn huma diġà moħbija. Dawn ix-xejriet għandhom ikunu siguri biżżejjed: il-loġika tan-negozju tinbidel ħafna drabi, li jżid ir-riskju li jiġu introdotti żbalji, l-ispiża tal-iżbalji għandha tibqa 'f'livell pjuttost baxx.

Iżda xorta waħda, x'għandu x'jaqsam miegħu BPM? Hemm ħafna għażliet għall-implimentazzjoni tal-fluss tax-xogħol...
Tabilħaqq, implimentazzjoni oħra tal-proċessi tan-negozju hija popolari ħafna fis-soluzzjonijiet tagħna - permezz tal-issettjar dikjarattiv tad-dijagramma tat-tranżizzjoni tal-istat u l-konnessjoni ta 'handlers bil-loġika tan-negozju għat-tranżizzjonijiet. Fl-istess ħin, l-istat li jiddetermina l-pożizzjoni attwali tad-"dokument" fil-proċess tan-negozju huwa attribut tad-"dokument" innifsu.

Integrazzjoni stil BPM
Hekk jidher il-proċess fil-bidu tal-proġett

Il-popolarità ta 'implimentazzjoni bħal din hija dovuta għas-sempliċità relattiva u l-veloċità tal-ħolqien ta' proċessi ta 'negozju lineari. Madankollu, hekk kif is-sistemi tas-softwer isiru aktar kumplessi, il-parti awtomatizzata tal-proċess tan-negozju tikber u ssir aktar kumplessa. Hemm bżonn ta 'dekompożizzjoni, użu mill-ġdid ta' partijiet ta 'proċessi, kif ukoll proċessi ta' forking sabiex kull fergħa tiġi esegwita b'mod parallel. Taħt kundizzjonijiet bħal dawn, l-għodda ssir inkonvenjenti, u d-dijagramma tat-tranżizzjoni tal-istat titlef il-kontenut tal-informazzjoni tagħha (l-interazzjonijiet tal-integrazzjoni mhumiex riflessi fid-dijagramma).

Integrazzjoni stil BPM
Dan huwa kif jidher il-proċess wara diversi iterazzjonijiet biex jiġu ċċarati r-rekwiżiti

It-triq 'il barra minn din is-sitwazzjoni kienet l-integrazzjoni tal-magna jBPM f'xi prodotti bl-aktar proċessi tan-negozju kumplessi. Fi żmien qasir, din is-soluzzjoni kellha xi suċċess: sar possibbli li jiġu implimentati proċessi tan-negozju kumplessi filwaqt li tinżamm dijagramma pjuttost informattiva u aġġornata fin-notazzjoni BPMN2.

Integrazzjoni stil BPM
Parti żgħira minn proċess tan-negozju kumpless

Fit-tul, is-soluzzjoni ma laħqitx l-aspettattivi: l-intensità għolja tax-xogħol tal-ħolqien ta 'proċessi tan-negozju permezz ta' għodod viżwali ma ppermettietx il-kisba ta 'indikaturi tal-produttività aċċettabbli, u l-għodda nnifisha saret waħda mill-aktar ma gustat fost l-iżviluppaturi. Kien hemm ukoll ilmenti dwar l-istruttura interna tal-magna, li wasslet għad-dehra ta 'ħafna "garża" u "krozzi".

L-aspett pożittiv ewlieni tal-użu ta 'jBPM kien ir-realizzazzjoni tal-benefiċċji u l-ħsarat li jkollu l-istat persistenti tiegħu stess għal istanza ta' proċess tan-negozju. Rajna wkoll il-possibbiltà li nużaw approċċ ta 'proċess biex jiġu implimentati protokolli ta' integrazzjoni kumplessi bejn applikazzjonijiet differenti li jużaw interazzjonijiet asinkroniċi permezz ta 'sinjali u messaġġi. Il-preżenza ta' stat persistenti għandha rwol kruċjali f'dan.

Abbażi ta 'hawn fuq, nistgħu nikkonkludu: L-approċċ tal-proċess fl-istil BPM jippermettilna nsolvu firxa wiesgħa ta 'ħidmiet għall-awtomatizzazzjoni ta' proċessi tan-negozju dejjem aktar kumplessi, nwaħħal b'mod armonjuż attivitajiet ta 'integrazzjoni f'dawn il-proċessi u nżommu l-abbiltà li nuru viżwalment il-proċess implimentat f'notazzjoni xierqa.

Żvantaġġi ta 'sejħiet sinkroniċi bħala mudell ta' integrazzjoni

L-integrazzjoni sinkronika tirreferi għall-iktar sejħa ta 'imblukkar sempliċi. Subsistema waħda taġixxi bħala n-naħa tas-server u tesponi l-API bil-metodu mixtieq. Subsistema oħra taġixxi bħala naħa tal-klijent u, fil-ħin it-tajjeb, tagħmel sejħa bl-istennija ta 'riżultat. Skont l-arkitettura tas-sistema, in-naħat tal-klijent u tas-server jistgħu jiġu ospitati jew fl-istess applikazzjoni u proċess, jew f'oħrajn differenti. Fit-tieni każ, għandek bżonn tapplika xi implimentazzjoni ta 'RPC u tipprovdi marshalling tal-parametri u r-riżultat tas-sejħa.

Integrazzjoni stil BPM

Tali mudell ta 'integrazzjoni għandu sett pjuttost kbir ta' żvantaġġi, iżda huwa użat ħafna fil-prattika minħabba s-sempliċità tiegħu. Il-veloċità tal-implimentazzjoni captivates u tagħmel inti tapplikaha għal darb'oħra u għal darb'oħra fil-kundizzjonijiet ta '"ħruq" skadenzi, tikteb is-soluzzjoni f'dejn tekniku. Iżda jiġri wkoll li żviluppaturi mingħajr esperjenza jużawha bla konxju, sempliċement ma jirrealizzawx il-konsegwenzi negattivi.

Minbarra ż-żieda l-aktar ovvja fil-konnettività tas-sottosistemi, hemm problemi inqas ovvji bit-tranżazzjonijiet ta '"tixrid" u "tiġbid". Tabilħaqq, jekk il-loġika tan-negozju tagħmel xi bidliet, allura t-tranżazzjonijiet huma indispensabbli, u t-tranżazzjonijiet, min-naħa tagħhom, jissakkru ċerti riżorsi tal-applikazzjoni affettwati minn dawn il-bidliet. Jiġifieri, sakemm subsistema waħda tistenna tweġiba minn oħra, ma tkunx tista 'tlesti t-tranżazzjoni u tirrilaxxa serraturi. Dan iżid b'mod sinifikanti r-riskju ta 'varjetà ta' effetti:

  • ir-rispons tas-sistema tintilef, l-utenti jistennew żmien twil għal tweġibiet għat-talbiet;
  • is-server ġeneralment jieqaf jirrispondi għat-talbiet tal-utent minħabba pool ta 'ħajt li jfur: ħafna mill-ħjut "joqgħod" fuq il-lock tar-riżors okkupat mit-tranżazzjoni;
  • Deadlocks jibdew jidhru: il-probabbiltà tal-okkorrenza tagħhom tiddependi ħafna fuq it-tul tat-tranżazzjonijiet, l-ammont ta 'loġika tan-negozju u serraturi involuti fit-tranżazzjoni;
  • jidhru żbalji ta' skadenza ta' timeout tat-tranżazzjoni;
  • is-server "jaqa '" fuq OutOfMemory jekk il-kompitu jeħtieġ l-ipproċessar u l-bdil ta' ammonti kbar ta 'dejta, u l-preżenza ta' integrazzjonijiet sinkroniċi tagħmilha diffiċli ħafna li l-ipproċessar jinqasam fi tranżazzjonijiet "eħfef".

Mil-lat arkitettoniku, l-użu ta 'sejħiet imblukkar waqt l-integrazzjoni jwassal għal telf ta' kontroll tal-kwalità ta 'sottosistemi individwali: huwa impossibbli li jiġu żgurati l-miri ta' kwalità ta 'subsistema waħda f'iżolament mill-miri ta' kwalità ta 'subsistema oħra. Jekk is-sottosistemi jiġu żviluppati minn timijiet differenti, din hija problema kbira.

L-affarijiet isiru saħansitra aktar interessanti jekk is-sottosistemi li qed jiġu integrati jkunu f'applikazzjonijiet differenti u jeħtieġ li jsiru bidliet sinkroniċi fuq iż-żewġ naħat. Kif tagħmel dawn il-bidliet transazzjonali?

Jekk isiru bidliet fi tranżazzjonijiet separati, allura jkun hemm bżonn li jiġu pprovduti trattament u kumpens robust ta 'eċċezzjoni, u dan jelimina kompletament il-vantaġġ ewlieni ta' integrazzjonijiet sinkroniċi - is-sempliċità.

Tranżazzjonijiet distribwiti jiġu f'moħħna wkoll, iżda aħna ma nużawhomx fis-soluzzjonijiet tagħna: huwa diffiċli li tiġi żgurata l-affidabbiltà.

"Saga" bħala soluzzjoni għall-problema tat-tranżazzjonijiet

Bil-popolarità dejjem tikber tal-mikroservizzi, hemm domanda dejjem tikber għal Mudell Saga.

Dan il-mudell issolvi perfettament il-problemi ta 'hawn fuq ta' tranżazzjonijiet twal, u jespandi wkoll il-possibbiltajiet ta 'ġestjoni tal-istat tas-sistema min-naħa tal-loġika tan-negozju: kumpens wara tranżazzjoni mingħajr suċċess jista' ma jreġġax lura s-sistema għall-istat oriġinali tagħha, iżda jipprovdi alternattiva rotta tal-ipproċessar tad-data. Jippermettilek ukoll li ma tirrepetix passi tal-ipproċessar tad-data li tlestew b'suċċess meta tipprova tressaq il-proċess għal tmiem "tajjeb".

Interessanti, f'sistemi monolitiċi, dan il-mudell huwa rilevanti wkoll meta niġu għall-integrazzjoni ta 'sottosistemi akkoppjati b'mod laxk u hemm effetti negattivi kkawżati minn tranżazzjonijiet twal u s-serraturi tar-riżorsi korrispondenti.

Fir-rigward tal-proċessi tan-negozju tagħna fl-istil BPM, jirriżulta li huwa faċli ħafna li timplimenta s-Sagas: il-passi individwali tas-Sagas jistgħu jiġu stabbiliti bħala attivitajiet fi ħdan il-proċess tan-negozju, u l-istat persistenti tal-proċess tan-negozju jiddetermina, fost affarijiet oħra, l-istat intern tas-Sagas. Jiġifieri, m'għandna bżonn l-ebda mekkaniżmu ta' koordinazzjoni addizzjonali. Kulma għandek bżonn huwa sensar tal-messaġġi b'appoġġ għal garanziji "mill-inqas darba" bħala trasport.

Iżda soluzzjoni bħal din għandha wkoll il-"prezz" tagħha stess:

  • Il-loġika tan-negozju ssir aktar kumplessa: trid taħdem il-kumpens;
  • ikun meħtieġ li tiġi abbandunata l-konsistenza sħiħa, li tista 'tkun speċjalment sensittiva għal sistemi monolitiċi;
  • l-arkitettura ssir ftit aktar ikkumplikata, hemm ħtieġa addizzjonali għal sensar tal-messaġġi;
  • se jkunu meħtieġa għodod addizzjonali ta 'monitoraġġ u amministrazzjoni (għalkemm b'mod ġenerali dan huwa saħansitra tajjeb: il-kwalità tas-servizz tas-sistema se tiżdied).

Għal sistemi monolitiċi, il-ġustifikazzjoni għall-użu ta '"Sags" mhix daqshekk ovvja. Għal mikroservizzi u SOAs oħra, fejn, x'aktarx, diġà hemm sensar, u l-konsistenza sħiħa ġiet sagrifikata fil-bidu tal-proġett, il-benefiċċji tal-użu ta 'dan il-mudell jistgħu jegħlbu b'mod sinifikanti l-iżvantaġġi, speċjalment jekk ikun hemm API konvenjenti fil- livell tal-loġika tan-negozju.

Inkapsulament tal-loġika tan-negozju fil-mikroservizzi

Meta bdejna nesperimentaw bil-mikroservizzi, qamet mistoqsija raġonevoli: fejn tpoġġi l-loġika tan-negozju tad-dominju f'relazzjoni mas-servizz li jipprovdi persistenza tad-dejta tad-dominju?

Meta tħares lejn l-arkitettura ta 'diversi BPMS, jista' jidher raġonevoli li tissepara l-loġika tan-negozju mill-persistenza: toħloq saff ta 'pjattaforma u mikroservizzi indipendenti mid-dominju li jiffurmaw l-ambjent u l-kontenitur għall-eżekuzzjoni tal-loġika tan-negozju tad-dominju, u tirranġa l-persistenza tad-dejta tad-dominju bħala separata. saff ta' mikroservizzi sempliċi ħafna u ħfief. Il-proċessi tan-negozju f'dan il-każ orkestraw is-servizzi tas-saff ta 'persistenza.

Integrazzjoni stil BPM

Dan l-approċċ għandu vantaġġ kbir ħafna: tista 'żżid il-funzjonalità tal-pjattaforma kemm trid, u s-saff korrispondenti tal-mikroservizzi tal-pjattaforma biss "jixxaħħam" minn dan. Proċessi tan-negozju minn kwalunkwe dominju immedjatament jiksbu l-opportunità li jużaw il-funzjonalità l-ġdida tal-pjattaforma hekk kif tiġi aġġornata.

Studju aktar dettaljat wera nuqqasijiet sinifikanti ta’ dan l-approċċ:

  • servizz ta 'pjattaforma li jesegwixxi l-loġika tan-negozju ta' ħafna oqsma f'daqqa jġorr riskji kbar bħala punt wieħed ta 'falliment. Bidliet frekwenti fil-loġika tan-negozju jżidu r-riskju ta 'bugs li jwasslu għal fallimenti fis-sistema kollha;
  • kwistjonijiet ta' prestazzjoni: il-loġika tan-negozju taħdem bid-dejta tagħha permezz ta' interface dejqa u bil-mod:
    • id-dejta għal darb'oħra se tkun miġbura u ppumpjata permezz tal-munzell tan-netwerk;
    • is-servizz tad-dominju spiss jirritorna aktar dejta milli teħtieġ il-loġika tan-negozju għall-ipproċessar, minħabba kapaċitajiet insuffiċjenti ta’ parametrizzazzjoni ta’ mistoqsijiet fil-livell tal-API esterna tas-servizz;
    • diversi biċċiet indipendenti ta 'loġika tan-negozju jistgħu ripetutament jerġgħu jitolbu l-istess data għall-ipproċessar (tista' ttaffi din il-problema billi żżid il-fażola tas-sessjoni li d-data fil-cache, iżda dan ikompli jikkomplika l-arkitettura u joħloq problemi ta 'freskezza tad-data u invalidazzjoni tal-cache);
  • kwistjonijiet transazzjonali:
    • proċessi tan-negozju bi stat persistenti maħżuna mis-servizz tal-pjattaforma huma inkonsistenti mad-dejta tad-dominju, u m'hemmx modi faċli biex issolvi din il-problema;
    • iċ-ċaqliq tas-serratura tad-dejta tad-dominju barra mit-tranżazzjoni: jekk il-loġika tan-negozju tad-dominju teħtieġ li tagħmel bidliet, wara li l-ewwel tiċċekkja l-korrettezza tad-dejta attwali, huwa meħtieġ li tiġi eskluża l-possibbiltà ta 'bidla kompetittiva fid-dejta pproċessata. L-imblukkar estern tad-dejta jista 'jgħin biex issolvi l-problema, iżda soluzzjoni bħal din iġorr riskji addizzjonali u tnaqqas l-affidabbiltà ġenerali tas-sistema;
  • kumplikazzjonijiet addizzjonali meta taġġorna: f'xi każijiet, għandek bżonn taġġorna s-servizz ta 'persistenza u l-loġika tan-negozju b'mod sinkroniku jew f'sekwenza stretta.

Fl-aħħar, kelli mmur lura għall-affarijiet bażiċi: inkapsulat id-dejta tad-dominju u l-loġika tan-negozju tad-dominju f'mikroservizz wieħed. Dan l-approċċ jissimplifika l-perċezzjoni tal-mikroservizz bħala komponent integrali fis-sistema u ma jagħtix lok għall-problemi ta 'hawn fuq. Dan ukoll mhux b'xejn:

  • L-istandardizzazzjoni tal-API hija meħtieġa għall-interazzjoni mal-loġika tan-negozju (b'mod partikolari, biex jiġu pprovduti attivitajiet tal-utent bħala parti mill-proċessi tan-negozju) u s-servizzi tal-pjattaforma tal-API; attenzjoni aktar bir-reqqa għall-bidliet API, il-kompatibilità bil-quddiem u b'lura hija meħtieġa;
  • huwa meħtieġ li jiżdiedu libreriji runtime addizzjonali biex jiġi żgurat il-funzjonament tal-loġika tan-negozju bħala parti minn kull mikroservizz bħal dan, u dan jagħti lok għal rekwiżiti ġodda għal libreriji bħal dawn: ħeffa u minimu ta 'dipendenzi tranżittivi;
  • L-iżviluppaturi tal-loġika tan-negozju jeħtieġ li jżommu rekord tal-verżjonijiet tal-libreriji: jekk mikroservizz ma jkunx ġie ffinalizzat għal żmien twil, allura x'aktarx ikun fih verżjoni skaduta tal-libreriji. Dan jista 'jkun ostaklu mhux mistenni biex tiżdied karatteristika ġdida u jista' jeħtieġ li l-loġika tan-negozju l-antika ta 'tali servizz tiġi emigrata għal verżjonijiet ġodda tal-libreriji jekk kien hemm bidliet inkompatibbli bejn il-verżjonijiet.

Integrazzjoni stil BPM

Saff ta 'servizzi ta' pjattaforma huwa wkoll preżenti f'tali arkitettura, iżda dan is-saff m'għadux jifforma kontenitur għall-eżekuzzjoni tal-loġika tan-negozju tad-dominju, iżda biss l-ambjent tiegħu, li jipprovdi funzjonijiet awżiljarji "pjattaforma". Tali saff huwa meħtieġ mhux biss biex iżżomm il-ħeffa tal-mikroservizzi tad-dominju, iżda wkoll biex tiċċentralizza l-ġestjoni.

Pereżempju, l-attivitajiet tal-utent fil-proċessi tan-negozju jiġġeneraw kompiti. Madankollu, meta jaħdem mal-kompiti, l-utent irid jara l-kompiti mid-dominji kollha fil-lista ġenerali, li jfisser li għandu jkun hemm servizz xieraq ta 'pjattaforma ta' reġistrazzjoni tal-kompiti, imneħħi mill-loġika tan-negozju tad-dominju. Iż-żamma tal-inkapsulament tal-loġika tan-negozju f'dan il-kuntest hija pjuttost problematika, u dan huwa kompromess ieħor ta 'din l-arkitettura.

Integrazzjoni ta 'proċessi tan-negozju permezz tal-għajnejn ta' żviluppatur tal-applikazzjoni

Kif diġà msemmi hawn fuq, l-iżviluppatur tal-applikazzjoni għandu jiġi estratt mill-karatteristiċi tekniċi u tal-inġinerija tal-implimentazzjoni tal-interazzjoni ta 'diversi applikazzjonijiet sabiex ikun jista' joqgħod fuq produttività tajba tal-iżvilupp.

Ejja nippruvaw insolvu problema ta 'integrazzjoni pjuttost diffiċli, ivvintata apposta għall-artikolu. Dan se jkun kompitu ta' "logħba" li jinvolvi tliet applikazzjonijiet, fejn kull waħda minnhom tiddefinixxi xi isem tad-dominju: "app1", "app2", "app3".

Ġewwa kull applikazzjoni, huma mnedija proċessi tan-negozju li jibdew "play ball" permezz tax-xarabank tal-integrazzjoni. Messaġġi bl-isem "Ball" se jaġixxu bħala l-ballun.

Regoli tal-logħba:

  • l-ewwel plejer huwa l-inizjatur. Huwa jistieden plejers oħra għal-logħba, jibda l-logħba u jista 'jtemmha fi kwalunkwe ħin;
  • plejers oħra jiddikjaraw il-parteċipazzjoni tagħhom fil-logħba, "jiffamiljarizzaw ruħhom" ma 'xulxin u l-ewwel plejer;
  • wara li jirċievi l-ballun, il-plejer jagħżel plejer ieħor parteċipanti u jgħaddilu l-ballun. In-numru totali ta’ passes jingħadd;
  • kull plejer għandu "enerġija", li tonqos ma' kull pass tal-ballun minn dak il-plejer. Meta tispiċċa l-enerġija, il-plejer jiġi eliminat mil-logħba, u jħabbar l-irtirar tagħhom;
  • jekk il-plejer jitħalla waħdu, immedjatament jiddikjara t-tluq tiegħu;
  • meta l-plejers kollha jiġu eliminati, l-ewwel plejer jiddikjara t-tmiem tal-logħba. Jekk ħalla l-logħba qabel, allura jibqa 'jsegwi l-logħba sabiex tlestiha.

Biex issolvi din il-problema, se nuża d-DSL tagħna għall-proċessi tan-negozju, li jippermettilek tiddeskrivi l-loġika f'Kotlin b'mod kompatt, b'minimu ta 'boilerplate.

Fl-applikazzjoni app1, il-proċess tan-negozju tal-ewwel plejer (huwa wkoll l-inizjatur tal-logħba) se jaħdem:

klassi 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}")
}

Minbarra l-eżekuzzjoni tal-loġika tan-negozju, il-kodiċi ta 'hawn fuq jista' jipproduċi mudell ta 'oġġett ta' proċess tan-negozju, li jista 'jiġi viżwalizzat bħala dijagramma. Għadna ma implimentajniex il-viżwalizzatur, għalhekk kellna nqattgħu ftit ħin tpinġi (hawnhekk issimplifikajt kemmxejn in-notazzjoni BPMN dwar l-użu ta 'gradi biex intejbu l-konsistenza tad-dijagramma bil-kodiċi ta' hawn fuq):

Integrazzjoni stil BPM

app2 se tinkludi l-proċess tan-negozju ta' plejer ieħor:

klassi 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}")
}

Dijagramma:

Integrazzjoni stil BPM

Fl-applikazzjoni app3, aħna se nagħmlu l-plejer b'imġieba kemmxejn differenti: minflok ma tagħżel b'mod każwali l-plejer li jmiss, se jaġixxi skont l-algoritmu round-robin:

klassi 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}")
}

Inkella, l-imġieba tal-plejer ma tvarjax minn dik preċedenti, għalhekk id-dijagramma ma tinbidilx.

Issa għandna bżonn test biex imexxuh kollu. Se nagħti biss il-kodiċi tat-test innifsu, sabiex ma nħaksx l-artiklu b'boilerplate (fil-fatt, użajt l-ambjent tat-test maħluq qabel biex nittestja l-integrazzjoni ta 'proċessi kummerċjali oħra):

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;
}

Mexxi t-test, ħares lejn il-ġurnal:

output tal-console

Взята блокировка ключа 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!

Minn dan kollu jistgħu jittieħdu diversi konklużjonijiet importanti:

  • jekk l-għodod meħtieġa huma disponibbli, l-iżviluppaturi tal-applikazzjonijiet jistgħu joħolqu interazzjonijiet ta 'integrazzjoni bejn l-applikazzjonijiet mingħajr ma jinkisru mil-loġika tan-negozju;
  • il-kumplessità (kumplessità) ta' kompitu ta' integrazzjoni li teħtieġ kompetenzi ta' inġinerija tista' tinħeba ġewwa l-qafas jekk inizjalment tkun stabbilita fl-arkitettura tal-qafas. Id-diffikultà tal-kompitu (diffikultà) ma tistax tinħeba, għalhekk is-soluzzjoni għal kompitu diffiċli fil-kodiċi se tħares kif xieraq;
  • meta tiġi żviluppata loġika ta 'integrazzjoni, huwa meħtieġ li eventwalment titqies il-konsistenza u n-nuqqas ta' linearizabilità tal-bidla fl-istat tal-parteċipanti kollha ta 'integrazzjoni. Dan iġiegħelna nikkomplikaw il-loġika sabiex nagħmluha insensittiva għall-ordni li fiha jseħħu l-avvenimenti esterni. Fl-eżempju tagħna, il-plejer huwa sfurzat jieħu sehem fil-logħba wara li jħabbar il-ħruġ tiegħu mil-logħba: plejers oħra jkomplu jgħaddulu l-ballun sakemm l-informazzjoni dwar il-ħruġ tiegħu tasal u tiġi pproċessata mill-parteċipanti kollha. Din il-loġika ma ssegwix mir-regoli tal-logħba u hija soluzzjoni ta 'kompromess fil-qafas tal-arkitettura magħżula.

Sussegwentement, ejja nitkellmu dwar id-diversi irqaq tas-soluzzjoni tagħna, kompromessi u punti oħra.

Il-messaġġi kollha f'kju wieħed

L-applikazzjonijiet integrati kollha jaħdmu b'xarabank ta 'integrazzjoni waħda, li hija ppreżentata bħala sensar estern, BPMQueue wieħed għall-messaġġi u suġġett wieħed BPMTopic għal sinjali (avvenimenti). Li tgħaddi l-messaġġi kollha minn kju wieħed huwa fih innifsu kompromess. Fil-livell tal-loġika tan-negozju, issa tista 'tintroduċi tipi ġodda ta' messaġġi kemm trid mingħajr ma tagħmel bidliet fl-istruttura tas-sistema. Din hija simplifikazzjoni sinifikanti, iżda ġġorr ċerti riskji, li, fil-kuntest tal-kompiti tipiċi tagħna, dehru lilna mhux daqshekk sinifikanti.

Integrazzjoni stil BPM

Madankollu, hawn sottilizza waħda: kull applikazzjoni tiffiltra l-messaġġi "tagħha" mill-kju fid-daħla, bl-isem tad-dominju tagħha. Ukoll, id-dominju jista 'jiġi speċifikat fis-sinjali, jekk għandek bżonn tillimita l-"ambitu" tas-sinjal għal applikazzjoni waħda. Dan għandu jżid il-bandwidth tax-xarabank, iżda l-loġika tan-negozju issa trid topera b'ismijiet ta 'dominju: obbligatorju għall-indirizzar tal-messaġġi, mixtieq għas-sinjali.

L-iżgurar tal-affidabbiltà tax-xarabank tal-integrazzjoni

L-affidabbiltà hija magħmula minn diversi affarijiet:

  • Is-sensar tal-messaġġ magħżul huwa komponent kritiku tal-arkitettura u punt wieħed ta' falliment: għandu jkun tolleranti biżżejjed għall-ħsarat. Għandek tuża biss implimentazzjonijiet ittestjati fil-ħin b'appoġġ tajjeb u komunità kbira;
  • huwa meħtieġ li tiġi żgurata disponibbiltà għolja tas-sensar tal-messaġġi, li għalih trid tkun fiżikament separata mill-applikazzjonijiet integrati (disponibbiltà għolja ta 'applikazzjonijiet b'loġika tan-negozju applikata hija ħafna aktar diffiċli u għalja biex tipprovdi);
  • is-sensar huwa obbligat li jipprovdi garanziji ta' konsenja "mill-inqas darba". Dan huwa rekwiżit obbligatorju għal tħaddim affidabbli tax-xarabank tal-integrazzjoni. M'hemmx bżonn ta' garanziji ta' livell "eżattament darba": il-proċessi tan-negozju ġeneralment mhumiex sensittivi għal riċevuta ripetuta ta' messaġġi jew avvenimenti, u f'ħidmiet speċjali fejn dan huwa importanti, huwa aktar faċli li żżid kontrolli addizzjonali mal-loġika tan-negozju milli tuża kontinwament pjuttost "għali" "garanziji;
  • li jintbagħtu messaġġi u sinjali għandhom ikunu involuti fi tranżazzjoni komuni b'bidla fl-istat tal-proċessi tan-negozju u d-dejta tad-dominju. L-għażla preferuta tkun li tuża l-mudell Outbox Transazzjonali, iżda se teħtieġ tabella addizzjonali fid-database u relay. Fl-applikazzjonijiet JEE, dan jista 'jiġi ssimplifikat bl-użu ta' maniġer JTA lokali, iżda l-konnessjoni mas-sensar magħżul trid tkun kapaċi taħdem fil-mod XA;
  • dawk li jimmaniġġjaw il-messaġġi u l-avvenimenti deħlin għandhom jaħdmu wkoll mat-tranżazzjoni tal-bidla tal-istat tal-proċess tan-negozju: jekk tranżazzjoni bħal din tiġi rritornata, allura l-irċevuta tal-messaġġ għandha tiġi kkanċellata wkoll;
  • messaġġi li ma setgħux jitwasslu minħabba żbalji għandhom jinħażnu f'maħżen separat D.L.Q. (Kju tal-Ittri Mejjet). Biex nagħmlu dan, ħloqna mikroservizz ta' pjattaforma separata li jaħżen messaġġi bħal dawn fil-ħażna tiegħu, indiċihom skont l-attributi (għal raggruppament u tiftix ta' malajr), u jesponi l-API biex tara, tibgħat mill-ġdid lill-indirizz tad-destinazzjoni, u tħassar messaġġi. L-amministraturi tas-sistema jistgħu jaħdmu ma' dan is-servizz permezz tal-interface tal-web tagħhom;
  • fis-settings tas-sensar, għandek bżonn taġġusta n-numru ta’ provi mill-ġdid tal-kunsinna u dewmien bejn il-kunsinni sabiex tnaqqas il-probabbiltà li messaġġi jidħlu fid-DLQ (huwa kważi impossibbli li tikkalkula l-aħjar parametri, iżda tista’ taġixxi empirikament u taġġustahom matul operazzjoni);
  • il-maħżen DLQ għandu jkun immonitorjat kontinwament, u s-sistema ta 'monitoraġġ għandha tinnotifika lill-amministraturi tas-sistema sabiex ikunu jistgħu jirrispondu malajr kemm jista' jkun meta jseħħu messaġġi mhux imwassla. Dan inaqqas iż-“żona ta’ ħsara” ta’ falliment jew żball ta’ loġika tan-negozju;
  • ix-xarabank ta 'integrazzjoni għandu jkun insensittiv għan-nuqqas temporanju ta' applikazzjonijiet: l-abbonamenti tas-suġġett għandhom ikunu dejjiema, u l-isem tad-dominju tal-applikazzjoni għandu jkun uniku sabiex xi ħadd ieħor ma jipprovax jipproċessa l-messaġġ tiegħu mill-kju waqt l-assenza tal-applikazzjoni.

L-iżgurar tas-sikurezza tal-ħajt tal-loġika tan-negozju

L-istess eżempju ta 'proċess tan-negozju jista' jirċievi diversi messaġġi u avvenimenti f'daqqa, li l-ipproċessar tagħhom jibda b'mod parallel. Fl-istess ħin, għal żviluppatur ta 'applikazzjoni, kollox għandu jkun sempliċi u bla periklu.

Il-loġika tan-negozju tal-proċess tipproċessa kull avveniment estern li jaffettwa dan il-proċess tan-negozju individwalment. Dawn l-avvenimenti jistgħu jkunu:

  • it-tnedija ta' istanza ta' proċess tan-negozju;
  • azzjoni tal-utent relatata ma' attività fi ħdan proċess tan-negozju;
  • irċevuta ta' messaġġ jew sinjal li għalih hija sottoskritta istanza ta' proċess tan-negozju;
  • l-iskadenza tat-tajmer issettjat mill-istanza tal-proċess tan-negozju;
  • azzjoni ta’ kontroll permezz ta’ API (eż. abort tal-proċess).

Kull avveniment bħal dan jista 'jbiddel l-istat ta' istanza ta 'proċess tan-negozju: xi attivitajiet jistgħu jispiċċaw u oħrajn jibdew, il-valuri ta' proprjetajiet persistenti jistgħu jinbidlu. L-għeluq ta' kwalunkwe attività jista' jirriżulta fl-attivazzjoni ta' waħda jew aktar mill-attivitajiet li ġejjin. Dawk, min-naħa tagħhom, jistgħu jieqfu jistennew avvenimenti oħra, jew, jekk ma jkollhomx bżonn xi dejta addizzjonali, jistgħu jlestu fl-istess tranżazzjoni. Qabel ma tagħlaq it-tranżazzjoni, l-istat il-ġdid tal-proċess tan-negozju jinħażen fid-database, fejn se jistenna l-avveniment estern li jmiss.

Dejta persistenti tal-proċess tan-negozju maħżuna f'database relazzjonali hija punt ta' sinkronizzazzjoni tal-ipproċessar konvenjenti ħafna meta tuża SELECT FOR UPDATE. Jekk tranżazzjoni waħda rnexxielha tikseb l-istat tal-proċess tan-negozju mid-database biex tibdelha, allura l-ebda transazzjoni oħra b'mod parallel ma tkun tista 'tikseb l-istess stat għal bidla oħra, u wara t-tlestija tal-ewwel tranżazzjoni, it-tieni waħda hija garantit li tirċievi l-istat diġà mibdul.

Bl-użu ta 'serraturi pessimisti fuq in-naħa tad-DBMS, aħna nissodisfaw ir-rekwiżiti kollha meħtieġa ACID, u żżomm ukoll il-kapaċità li tiskala l-applikazzjoni bil-loġika tan-negozju billi żżid in-numru ta 'istanzi li qed jaħdmu.

Madankollu, serraturi pessimisti jhedduna b'deadlocks, li jfisser li SELECT FOR UPDATE xorta għandha tkun limitata għal xi timeout raġonevoli f'każ ta 'deadlocks fuq xi każijiet egreġji fil-loġika tan-negozju.

Problema oħra hija s-sinkronizzazzjoni tal-bidu tal-proċess tan-negozju. Filwaqt li m'hemm l-ebda istanza tal-proċess tan-negozju, m'hemm l-ebda stat fid-database lanqas, għalhekk il-metodu deskritt mhux se jaħdem. Jekk trid tiżgura l-uniċità ta 'istanza ta' proċess tan-negozju f'ambitu partikolari, allura għandek bżonn xi tip ta 'oġġett ta' sinkronizzazzjoni assoċjat mal-klassi tal-proċess u l-ambitu korrispondenti. Biex issolvi din il-problema, nużaw mekkaniżmu ta 'qfil differenti li jippermettilna nieħdu lock fuq riżors arbitrarju speċifikat minn ċavetta f'format URI permezz ta' servizz estern.

Fl-eżempji tagħna, il-proċess tan-negozju InitialPlayer fih dikjarazzjoni

uniqueConstraint = UniqueConstraints.singleton

Għalhekk, ir-reġistru fih messaġġi dwar it-teħid u r-rilaxx tas-serratura taċ-ċavetta korrispondenti. M'hemm l-ebda messaġġi bħal dawn għal proċessi oħra tan-negozju: uniqueConstraint mhuwiex stabbilit.

Problemi tal-proċess tan-negozju bi stat persistenti

Kultant li jkollok stat persistenti mhux biss jgħin, iżda wkoll ifixkel l-iżvilupp.
Il-problemi jibdew meta jkollok bżonn tagħmel bidliet fil-loġika tan-negozju u/jew fil-mudell tal-proċess tan-negozju. L-ebda bidla bħal din ma tinstab li hija kompatibbli mal-istat antik tal-proċessi tan-negozju. Jekk hemm ħafna każijiet "ħaj" fid-database, allura li tagħmel bidliet inkompatibbli jista 'jikkawża ħafna problemi, li ħafna drabi ltqajna magħhom meta nużaw jBPM.

Skont il-fond tal-bidla, tista 'taġixxi b'żewġ modi:

  1. toħloq tip ġdid ta 'proċess tan-negozju sabiex ma tagħmilx bidliet inkompatibbli ma' dak il-qadim, u użah minflok il-qadim meta tibda istanzi ġodda. L-istanzi qodma se jkomplu jaħdmu "bil-mod antik";
  2. jemigra l-istat persistenti tal-proċessi tan-negozju meta taġġorna l-loġika tan-negozju.

L-ewwel mod huwa aktar sempliċi, iżda għandu l-limitazzjonijiet u l-iżvantaġġi tiegħu, pereżempju:

  • duplikazzjoni tal-loġika tan-negozju f'ħafna mudelli ta 'proċess tan-negozju, żieda fil-volum tal-loġika tan-negozju;
  • ħafna drabi tkun meħtieġa tranżizzjoni immedjata għal loġika kummerċjali ġdida (kważi dejjem f'termini ta 'kompiti ta' integrazzjoni);
  • l-iżviluppatur ma jafx f'liema punt huwa possibbli li tħassar mudelli skaduti.

Fil-prattika, nużaw iż-żewġ approċċi, iżda ħadna numru ta’ deċiżjonijiet biex nissimplifikaw ħajjitna:

  • fid-database, l-istat persistenti tal-proċess tan-negozju huwa maħżun f'forma li tinqara faċilment u pproċessata faċilment: f'sekwenza ta 'format JSON. Dan jippermettilek li twettaq migrazzjonijiet kemm ġewwa l-applikazzjoni kif ukoll barra. F'każijiet estremi, tista 'wkoll tweak b'pumi (speċjalment utli fl-iżvilupp waqt id-debugging);
  • il-loġika tan-negozju ta 'integrazzjoni ma tużax l-ismijiet tal-proċessi tan-negozju, sabiex fi kwalunkwe ħin ikun possibbli li tissostitwixxi l-implimentazzjoni ta' wieħed mill-proċessi parteċipanti b'wieħed ġdid, b'isem ġdid (per eżempju, "InitialPlayerV2"). L-irbit iseħħ permezz tal-ismijiet tal-messaġġi u s-sinjali;
  • il-mudell tal-proċess għandu numru tal-verżjoni, li aħna nżidu jekk nagħmlu bidliet inkompatibbli għal dan il-mudell, u dan in-numru jinħażen flimkien mal-istat tal-istanza tal-proċess;
  • l-istat persistenti tal-proċess jinqara mill-bażi l-ewwel f'mudell ta 'oġġett konvenjenti li l-proċedura ta' migrazzjoni tista 'taħdem miegħu jekk in-numru tal-verżjoni tal-mudell ikun inbidel;
  • il-proċedura tal-migrazzjoni titqiegħed ħdejn il-loġika tan-negozju u tissejjaħ "għażżien" għal kull istanza tal-proċess tan-negozju fil-ħin tar-restawr tagħha mid-database;
  • jekk għandek bżonn temigra l-istat tal-istanzi kollha tal-proċess malajr u b'mod sinkroniku, jintużaw soluzzjonijiet ta 'migrazzjoni ta' database aktar klassiċi, iżda trid taħdem ma 'JSON hemmhekk.

Għandi bżonn qafas ieħor għall-proċessi tan-negozju?

Is-soluzzjonijiet deskritti fl-artikolu ppermettewlna nissimplifikaw ħajjitna b'mod sinifikanti, nespandu l-firxa ta 'kwistjonijiet solvuti fil-livell tal-iżvilupp tal-applikazzjoni, u nagħmlu l-idea li nisseparaw il-loġika tan-negozju f'mikroservizzi aktar attraenti. Għal dan, sar ħafna xogħol, inħoloq qafas "ħfief" ħafna għall-proċessi tan-negozju, kif ukoll komponenti ta 'servizz għas-soluzzjoni tal-problemi identifikati fil-kuntest ta' firxa wiesgħa ta 'kompiti applikati. Għandna xewqa li naqsmu dawn ir-riżultati, li nġibu l-iżvilupp ta 'komponenti komuni f'aċċess miftuħ taħt liċenzja ħielsa. Dan se jeħtieġ xi sforz u ħin. Il-fehim tad-domanda għal soluzzjonijiet bħal dawn jista' jkun inċentiv addizzjonali għalina. Fl-artikolu propost, ftit li xejn tingħata attenzjoni lill-kapaċitajiet tal-qafas innifsu, iżda xi wħud minnhom huma viżibbli mill-eżempji ppreżentati. Jekk madankollu nippubblikaw il-qafas tagħna, se jiġi ddedikat artiklu separat għalih. Sadanittant, inkunu grati jekk tħalli ftit feedback billi twieġeb il-mistoqsija:

Utenti reġistrati biss jistgħu jipparteċipaw fl-istħarriġ. Idħol, ta 'xejn.

Għandi bżonn qafas ieħor għall-proċessi tan-negozju?

  • 18,8%Iva, ilni żmien twil infittex xi ħaġa bħal din.

  • 12,5%huwa interessanti li titgħallem aktar dwar l-implimentazzjoni tiegħek, jista 'jkun utli2

  • 6,2%nużaw wieħed mill-oqfsa eżistenti, iżda qed naħsbu biex nissostitwixxuh1

  • 18,8%nużaw wieħed mill-oqfsa eżistenti, kollox suits3

  • 18,8%ilaħħqu mingħajr qafas3

  • 25,0%ikteb tiegħek4

Ivvutaw 16 utent. 7 utenti astjenew.

Sors: www.habr.com

Żid kumment