entegrasyona şêwaza BPM

entegrasyona şêwaza BPM

Slav, Habr!

Pargîdaniya me di pêşvebirina çareseriyên nermalava pola ERP-ê de pispor e, para şêrê ya ku ji hêla pergalên danûstendinê ve bi mentiqa karsaziyek pir mezin û herikîna belgeyê a la EDMS ve tê dagir kirin. Guhertoyên heyî yên hilberên me li ser teknolojiyên JavaEE-yê têne çêkirin, lê em di heman demê de bi mîkroxizmetan re bi awayekî çalak diceribînin. Yek ji wan deverên herî pirsgirêk ên çareseriyên weha yekbûna bine-pergalên cihêreng ên girêdayî domên cîran e. Pirsgirêkên entegrasyonê her gav serêşiyek mezin daye me, bêyî ku şêwazên mîmarî, stûnên teknolojiyê û çarçoweyên ku em bikar tînin, lê di van demên dawî de di çareserkirina pirsgirêkên weha de pêşkeftinek heye.

Di gotara ku ez ji we re radigihînim, ez ê li ser ezmûn û lêkolîna mîmarî ya ku NPO Krista li qada destnîşankirî heye biaxivim. Em ê her weha li mînakek çareseriyek hêsan a pirsgirêkek entegrasyonê ji nihêrîna pêşdebirek serîlêdanê binihêrin û fêr bibin ka çi li pişt vê sadebûnê veşartî ye.

Disclaimer

Çareseriyên mîmarî û teknîkî yên ku di gotarê de têne diyar kirin ji hêla min ve li ser bingeha ezmûna kesane di çarçoveya karên taybetî de têne pêşniyar kirin. Van çareseriyên hanê îdia nakin ku gerdûnî ne û dibe ku di bin şert û mercên din ên karanîna de ne çêtirîn bin.

Çi têkiliya BPM bi wê re heye?

Ji bo bersiva vê pirsê, em hewce ne ku hinekî kûrtir li ser taybetîyên pirsgirêkên sepandî yên çareseriyên xwe bigerin. Beşa sereke ya mantiqa karsaziyê di pergala meya danûstendinê ya tîpîk de ev e ku daneyan bi navgîniya bikarhêner, verastkirina bi destan û otomatîk a vê daneyê, rêvekirina wê di nav hin xebata xebatê de, weşandina wê li pergalek din / databasa analîtîk / arşîv, û çêkirina raporan di nav databasê de ye. . Bi vî rengî, fonksiyona sereke ya pergalê ji bo xerîdaran otomatîkkirina pêvajoyên karsaziya wan a navxweyî ye.

Ji bo rehetiyê, em di ragihandinê de têgîna "belge" wekî hin berhevokek komek daneyan ku ji hêla mifteyek hevpar ve hatî yek kirin bikar tînin ku karekî diyarkirî dikare jê re "girêdayî" be.
Lê mentiqê entegrasyonê çi ye? Beriya her tiştî, peywira entegrasyonê ji hêla mîmariya pergalê ve, ku NE li ser daxwaza xerîdar, lê di bin bandora faktorên bi tevahî cûda de, li beşan tê "birrîn" tête çêkirin:

  • mijara qanûna Conway;
  • wekî encama ji nû ve karanîna bine pergalên ku berê ji bo hilberên din hatine pêşve xistin;
  • li ser daxwaza mîmarê, li ser bingeha pêdiviyên ne-fonksîyonel.

Ceribandinek mezin heye ku meriv mantiqa entegrasyonê ji mantiqa karsaziya xebata sereke veqetîne, da ku meriv mantiqa karsaziyê bi hunerên entegrasyonê pîs neke û pêşdebirê serîlêdanê ji hewcedariya kûrbûna nav taybetmendiyên perestgeha mîmarî ya pergalê rehet neke. Ev nêzîkatî çend avantajên xwe hene, lê pratîk bêbandoriya wê nîşan dide:

  • çareserkirina pirsgirêkên entegrasyonê bi gelemperî vedigere vebijarkên herî hêsan ên di forma bangên hevdem de ji ber xalên dirêjkirina tixûbdar ên di pêkanîna xebata sereke de (dezawantajên entegrasyona hevdem li jêr têne nîqaş kirin);
  • dema ku bersivek ji bine-pergalek din hewce ye, hunerên entegrasyonê hîn jî di nav mantiqa karsaziya bingehîn de derbas dibin;
  • pêşdebirê serîlêdanê entegrasyonê paşguh dike û bi guheztina tevgera xebatê bi hêsanî dikare wê bişkîne;
  • pergal ji nihêrîna bikarhêner de namîne yek yekane, "qelp" di navbera binepergalan de xuya dibin, û operasyonên bikarhêner ên zêde xuya dibin, ku veguheztina daneyan ji binepergalek din dest pê dike.

Nêzîktêdayînek din ev e ku meriv danûstendinên entegrasyonê wekî parçeyek bingehîn a mantiqa karsaziya bingehîn û xebata xebatê bihesibîne. Ji bo ku nehêle ku kalîteyên pêşdebirên serîlêdanê ji asîman bilind bibin, afirandina danûstendinên entegrasyonê yên nû divê hêsan û bêhêz be, bi fersendek hindiktirîn a hilbijartina çareseriyekê. Ev ji ya ku xuya dike dijwartir e: amûr divê ew qas hêzdar be ku ji bo karanîna xwe vebijarkên cûrbecûr yên pêwîst ji bikarhêner re peyda bike, bêyî ku destûrê bide wî ku "xwe di lingê xwe de biteqîne." Gelek pirs hene ku endezyarek divê di çarçoveya karên entegrasyonê de bersivê bide, lê ku pêşdebirek serîlêdanê divê di xebata xwe ya rojane de li ser wan nefikire: sînorên danûstendinê, hevgirtî, atomî, ewlehî, pîvandin, barkirin û belavkirina çavkaniyê, rêkirin, marşakirin, danûstendinên belavkirin û guherandinê, hwd. Pêdivî ye ku ji pêşdebirên sepanê re şablonên çareseriyê yên pir hêsan pêşkêşî bikin ku bersivên hemî pirsên weha jixwe tê de veşartî ne. Pêdivî ye ku ev şablon pir ewledar bin: mantiqa karsaziyê pir caran diguhezîne, ku xetera danasîna xeletiyan zêde dike, lêçûna xeletiyan divê di astek pir kêm de bimîne.

Lê çi têkiliya BPM bi wê re heye? Gelek vebijark hene ji bo pêkanîna xebata xebatê ...
Bi rastî, pêkanînek din a pêvajoyên karsaziyê di çareseriyên me de pir populer e - bi navgîniya pênasekirina diyarker a diyagramek veguheztina dewletê û girêdana destanan bi mantiqa karsaziyê ya ji bo veguheztinê. Di vê rewşê de, dewleta ku di pêvajoya karsaziyê de pozîsyona heyî ya "belge" diyar dike, taybetmendiyek "belge" bixwe ye.

entegrasyona şêwaza BPM
Ev pêvajo di destpêka projeyekê de xuya dike

Popularîteya vê pêkanînê ji ber sadebûn û leza çêkirina pêvajoyên karsaziya xêzkirî ye. Lêbelê, her ku pergalên nermalavê bi domdarî tevlihevtir dibin, beşa otomatîkî ya pêvajoya karsaziyê mezin dibe û tevlihevtir dibe. Pêwîstî bi hilweşandin, ji nû ve bikaranîna beşên pêvajoyan, û her weha pêvajoyên şaxkirinê heye ku her şaxek bi hev re were darve kirin. Di bin şert û mercên weha de, amûr nerehet dibe, û diyagrama veguheztina dewletê naveroka agahdariya xwe winda dike (danûstendinên entegrasyonê bi tevahî di diagramê de nayê xuyang kirin).

entegrasyona şêwaza BPM
Ev e ya ku pêvajo piştî çend dubareyên zelalkirina hewcedariyên xuya dike.

Rêya derketina ji vê rewşê entegrasyona motorê bû jBPM nav hin hilberan de bi pêvajoyên karsaziyê yên herî tevlihev. Di demek kurt de, ev çareserî hin serketî bû: îmkan bû ku meriv pêvajoyên karsaziyê yên tevlihev bicîh bîne dema ku di nîgarê de nexşeyek pir agahdar û têkildar biparêze. BPMN2.

entegrasyona şêwaza BPM
Parçeyek piçûk a pêvajoyek karsaziyek tevlihev

Di demek dirêj de, çareserî hêviyên xwe pêk neanî: zedebûna kedê ya afirandina pêvajoyên karsaziyê bi navgîniya amûrên dîtbarî nehişt ku bigihîje nîşaneyên hilberîna pejirandî, û amûr bixwe bû yek ji wan ên herî nefret di nav pêşdebiran de. Di heman demê de gilî li ser strukturên hundurîn ên motorê jî hebûn, ku bû sedema xuyangiya gelek "paçik" û "qirç"an.

Aliyê bingehîn ê erênî ya karanîna jBPM-ê haydariya feyde û zirarên hebûna rewşa domdar a mînakek pêvajoya karsaziyê bû. Me di heman demê de îhtîmala karanîna pêvajoyek ji bo pêkanîna protokolên entegrasyonê yên tevlihev di navbera serîlêdanên cihêreng de bi karanîna danûstendinên asynchronous bi navgîn û peyaman ve dît. Hebûna dewleteke bi israr di vê de roleke girîng dilîze.

Li ser bingeha jorîn, em dikarin encam bikin: Nêzîkatiya pêvajoyê di şêwaza BPM-ê de dihêle ku em cûrbecûr peywiran çareser bikin da ku pêvajoyên karsaziyê yên her ku diçe tevlihevtir otomatîk bikin, çalakiyên entegrasyonê bi ahengî di nav van pêvajoyan de bicîh bikin û kapasîteya ku bi dîtbarî pêvajoya pêkanînê bi nîşanek guncan nîşan bidin biparêzin.

Dezawantajên bangên hevdem wekî nimûneyek entegrasyonê

Yekbûna hevdemî banga astengkirina herî hêsan e. Yek bine-pergalê wekî aliyê serverê tevdigere û API-ê bi rêbaza pêwîst eşkere dike. Subpergalek din wekî aliyê xerîdar tevdigere û di wextê rast de bangek dike û li benda encamê ye. Bi mîmariya pergalê ve girêdayî, aliyên xerîdar û serverê dikarin di heman serîlêdan û pêvajoyê de, an jî di yên cûda de cih bigirin. Di doza duyemîn de, hûn hewce ne ku hin pêkanîna RPC-ê bicîh bikin û marşakirina pîvanan û encama bangê peyda bikin.

entegrasyona şêwaza BPM

Ev şêwaza entegrasyonê komek kêmasiyên pir mezin heye, lê ji ber sadebûna xwe di pratîkê de pir berfireh tê bikar anîn. Leza pêkanînê dîl digire û we neçar dike ku hûn wê dîsa û dîsa li ber demên zordar bikar bînin, çareseriyê wekî deynê teknîkî tomar bikin. Lê di heman demê de diqewime ku pêşdebirên bê tecrube wê bêhiş bikar tînin, bi tenê encamên neyînî fam nakin.

Ji bilî zêdebûna herî eşkere ya girêdana bine-pergalê, di nav danûstendinên "mezinbûn" û "dirêjkirin" de pirsgirêkên kêmtir eşkere jî hene. Bi rastî, heke mantiqa karsaziyê hin guhertinan çêbike, wê hingê ji danûstendinan nayê dûrxistin, û danûstendin, di encamê de, hin çavkaniyên serîlêdanê yên ku ji van guhertinan bandor bûne asteng dikin. Ango heta ku binepergalek li benda bersivek ji ya din be, ew ê nikaribe danûstendinê biqedîne û qefleyan rake. Ev xetera cûrbecûr bandorên girîng zêde dike:

  • Bersivdana pergalê winda dibe, bikarhêner demek dirêj li benda bersivên pirsan in;
  • pêşkêşker bi gelemperî bersivdana daxwazên bikarhêneran rawestîne ji ber hewza têlefonê ya pir qerebalix: piraniya mijaran li ser çavkaniyek ku ji hêla danûstendinek ve hatî dagir kirin têne girtin;
  • Xemgînî dest pê dikin: îhtîmala rûdana wan bi zexm bi dirêjahiya danûstendinan, mêjera mantiqa karsaziyê û kilîdên ku di danûstendinê de têkildar in ve girêdayî ye;
  • xeletiyên dema danûstandinê xuya dibin;
  • server bi OutOfMemory re "serneket" heke peywir pêdivî bi pêvajokirin û guheztina mîqdarên mezin ên daneyê hebe, û hebûna entegrasyonên hevdemî dabeşkirina pêvajoyê li danûstendinên "siviktir" pir dijwar dike.

Ji hêla mîmarî ve, karanîna bangên astengkirinê di dema entegrasyonê de dibe sedema windakirina kontrolê li ser kalîteya binepergalên kesane: ne gengaz e ku meriv nîşaneyên kalîteya armancê ya yek binepergalê bi veqetandina ji nîşangirên kalîteyê yên binepergalek din piştrast bike. Ger jêrpergal ji hêla tîmên cûda ve têne pêşve xistin, ev pirsgirêkek mezin e.

Ger bine pergalên ku têne yek kirin di sepanên cihêreng de bin û pêdivî ye ku hûn li her du aliyan guheztinên hevdem bikin, tişt hê balkêştir dibin. Meriv çawa danûstendina van guhertinan piştrast dike?

Ger guheztin di danûstendinên cihêreng de bêne çêkirin, wê hingê hûn ê hewce bikin ku îstîsna û tezmînata pêbawer peyda bikin, û ev bi tevahî berjewendiya sereke ya entegrasyonên hevdem - sadebûn - ji holê radike.

Danûstandinên belavkirî jî têne bîra me, lê em wan di çareseriyên xwe de bikar naynin: zehmet e ku meriv pêbaweriyê misoger bike.

"Saga" wekî çareseriya pirsgirêka danûstendinê

Bi zêdebûna populerbûna mîkroxizmetan re, daxwazî ​​​​ji bo Saga Pattern.

Ev nimûne bi tevahî pirsgirêkên danûstendinên dirêj ên jorîn çareser dike, û di heman demê de kapasîteyên birêvebirina rewşa pergalê ji hêla mantiqa karsaziyê ve berfireh dike: tezmînata piştî danûstendinek têkçûyî dibe ku pergalê venegerîne rewşa xweya bingehîn, lê peyda dike. rêgezek hilberandina daneyê ya alternatîf. Ev di heman demê de dihêle hûn gava ku hûn hewl didin ku pêvajoyê bigihînin dawiya "baş" ji dubarekirina gavên hilberandina daneya bi serfirazî qediyan dûr bixin.

Balkêş e, di pergalên yekparêz de ev şêwaz di heman demê de têkildar e dema ku ew tê ser yekbûna bine-pergalên bi hev ve girêdayî û bandorên neyînî yên ku ji hêla danûstendinên demdirêj ve têne çêkirin û kilîdên çavkaniyê yên têkildar têne dîtin.

Têkiliya pêvajoyên karsaziya me ya di şêwaza BPM-ê de, pêkanîna "Sagas" pir hêsan derdikeve holê: gavên takekesî yên "Saga" dikarin wekî çalakiyên di pêvajoya karsaziyê de bêne destnîşan kirin, û rewşa domdar a pêvajoya karsaziyê jî. rewşa navxweyî ya "Saga" diyar dike. Ango pêwîstiya me bi mekanîzmayeke zêde ya koordînasyonê nîne. Tişta ku hûn hewce ne brokerek peyamê ye ku wekî veguheztinê garantiyên "bi kêmî carekê" piştgirî dike.

Lê ev çareserî jî "bihayê" xwe heye:

  • mantiqa karsaziyê tevlihevtir dibe: pêdivî ye ku tezmînat were xebitandin;
  • Pêdivî ye ku meriv dev ji hevgirtina tam berde, ku dikare bi taybetî ji bo pergalên yekparêz hesas be;
  • Mîmarî hinekî tevlihevtir dibe, û pêdiviya zêde ji bo brokerek peyamê xuya dike;
  • Amûrên çavdêrî û rêveberiyê yên din hewce ne (her çend bi gelemperî ev baş e: dê kalîteya karûbarê pergalê zêde bibe).

Ji bo pergalên monolîtîk, rastdariya karanîna "Sag" ne ew qas eşkere ye. Ji bo mîkroxizmet û SOA-yên din, ku bi îhtîmalek mezin jixwe brokerek heye, û di destpêka projeyê de domdariya tam tê qurban kirin, feydeyên karanîna vê nimûneyê dikare bi girîngî ji dezawantajên girantir bibe, nemaze heke di mantiqa karsaziyê de API-yek rehet hebe. deşt.

Di mîkroxizmetan de mantiqa karsaziyê vedihewîne

Dema ku me dest bi ceribandina mîkroxizmetan kir, pirsek maqûl derket holê: meriv mantiqa karsaziya domainê li ku derê bi karûbarê ku domdariya daneyên domainê misoger dike ve bi cîh bike?

Gava ku meriv li mîmariya BPMS-yên cihêreng dinihêre, dibe ku maqûl xuya bike ku meriv mantiqa karsaziyê ji domdariyê veqetîne: qatek platform û mîkroxizmetên serbixwe-domîn biafirînin ku ji bo pêkanîna mantiqa karsaziya domainê jîngehek û konteynir çêbikin, û domdariya daneya domainê wekî sêwiran bikin. qatek cihêreng a mîkroxizmetên pir hêsan û sivik. Pêvajoyên karsaziyê di vê rewşê de orkestrasyona karûbarên qata domdariyê pêk tîne.

entegrasyona şêwaza BPM

Ev nêzîkatiyek xwedan avantajek pir mezin e: hûn dikarin fonksiyona platformê bi qasî ku hûn dixwazin zêde bikin, û tenê qata têkildar a mîkroxizmetên platformê dê ji vê yekê "qelew" bibe. Pêvajoyên karsaziyê ji her domainê tavilê gava ku ew nûve kirin tavilê dikarin fonksiyona nû ya platformê bikar bînin.

Lêkolînek berfirehtir kêmasiyên girîng ên vê nêzîkbûnê eşkere kir:

  • karûbarek platformê ku mantiqa karsaziya gelek domanan bi yekcarî pêk tîne wekî xalek têkçûnek yekane xetereyên mezin hildigire. Guhertinên pir caran di mantiqa karsaziyê de xetera xeletiyên ku dibin sedema têkçûna pergalê ya berfireh zêde dike;
  • Pirsgirêkên performansê: mantiqa karsaziyê bi daneyên xwe re bi navgînek teng û hêdî dixebite:
    • Daneyên wê careke din werin berhev kirin û di nav stûna torê de werin derxistin;
    • karûbarek domainê bi gelemperî ji ber ku ji bo pêvajoykirina mantiqa karsaziyê hewce dike bêtir daneyan peyda dike ji ber kêmasiyên ji bo parametrekirina daxwazên di asta API-ya derveyî ya karûbarê de;
    • çend perçeyên serbixwe yên mantiqa karsaziyê dikarin dubare ji bo pêvajoyê heman daneyan ji nû ve bixwazin (ev pirsgirêk dikare bi lêzêdekirina hêmanên danişînê yên ku daneyan cache dikin were kêm kirin, lê ev mîmariyê bêtir tevlihev dike û pirsgirêkên têkildariya daneyê û betalkirina cache-ê çêdike);
  • pirsgirêkên danûstendinê:
    • pêvajoyên karsaziyê yên bi dewleta domdar, ku ji hêla karûbarek platformê ve têne hilanîn, bi daneyên domainê re naguncan in, û ji bo çareserkirina vê pirsgirêkê rêyên hêsan tune;
    • danîna astengkirina daneya domainê li derveyî danûstendinê: heke mentiqê karsaziya domainê hewce bike ku piştî ku yekem rast rastdariya daneyên heyî kontrol bike guheztinan çêbike, pêdivî ye ku îhtîmala guherînek pêşbaziyê ya di daneyên pêvajoyî de were derxistin. Astengkirina daneya derveyî dikare alîkariya çareserkirina pirsgirêkê bike, lê çareseriyek wusa xetereyên din hildigire û pêbaweriya giştî ya pergalê kêm dike;
  • zehmetiyên zêde di dema nûvekirinê de: Di hin rewşan de, karûbarê domdar û mantiqa karsaziyê hewce ye ku bi hevdemî an bi rêzek hişk were nûve kirin.

Di dawiyê de, neçar ma ku em vegerin ser bingehên bingehîn: Daneyên domain û mantiqa karsaziya domainê di yek mîkroxizmetê de vedihewînin. Ev nêzîkatî têgihîştina mîkroxizmetek wekî hêmanek yekbûyî ya pergalê hêsan dike û pirsgirêkên jorîn dernakeve. Ev jî belaş nayê dayîn:

  • Standardkirina API-ê ji bo danûstendina bi mantiqa karsaziyê (bi taybetî, ji bo peydakirina çalakiyên bikarhêner wekî beşek pêvajoyên karsaziyê) û karûbarên platforma API-yê hewce ye; ji bo guhertinên API-ê, lihevhatina pêş û paş ve bêtir baldarî hewce dike;
  • Pêdivî ye ku pirtûkxaneyên dema xebitandinê yên din lê zêde bikin da ku karûbarê mantiqa karsaziyê wekî beşek ji her mîkroxizmetek wusa piştrast bikin, û ev yek ji bo pirtûkxaneyên weha hewcedariyên nû derdixe holê: sivikbûn û kêmtirîn girêdanên gerguhêz;
  • Pêşdebirên mantiqa karsaziyê hewce ne ku guhertoyên pirtûkxaneyê bişopînin: heke mîkroxizmetek ji bo demek dirêj ve nehatibe qedandin, wê hingê bi îhtîmalek mezin ew ê guhertoyek kevnar a pirtûkxaneyan bigire. Ev dikare bibe astengiyek neçaverêkirî ji bo lê zêdekirina taybetmendiyek nû û dibe ku hewce bike ku mantiqa karsaziya kevn a karûbarek wusa koçî guhertoyên nû yên pirtûkxaneyan bike heke di navbera guhertoyan de guhertinên nehevgirtî hebin.

entegrasyona şêwaza BPM

Di mîmariyek wusa de qatek karûbarên platformê jî heye, lê ev qat êdî ne konteynirek ji bo pêkanîna mantiqa karsaziya domainê, lê tenê hawîrdora wê pêk tîne, fonksiyonên "platform" ên alîkar peyda dike. Qatek wusa ne tenê ji bo domandina xwezaya sivik a mîkroxizmetên domainê, lê di heman demê de ji bo navendîkirina rêveberiyê jî hewce ye.

Mînakî, çalakiyên bikarhêner di pêvajoyên karsaziyê de peywiran çêdikin. Lêbelê, dema ku bi peywiran re dixebite, pêdivî ye ku bikarhêner di navnîşa gelemperî de peywiran ji hemî domanan bibîne, ku tê vê wateyê ku divê karûbarek qeydkirina peywira platformê ya têkildar hebe, ji mantiqa karsaziya domainê were paqij kirin. Di çarçoveyek wusa de domandina mentiqê karsaziyê pir pirsgirêk e, û ev lihevkirinek din a vê mîmariyê ye.

Yekbûna pêvajoyên karsaziyê bi çavên pêşdebirek serîlêdanê

Wekî ku li jor hatî behs kirin, pêdivî ye ku pêşdebirek serîlêdanê ji taybetmendiyên teknîkî û endezyariyê yên pêkanîna danûstendina çend serîlêdanan were derxistin da ku meriv bikaribe li ser hilberîna pêşkeftina baş hesab bike.

Ka em hewl bidin ku pirsgirêkek entegrasyonê ya pir dijwar, ku bi taybetî ji bo gotarê hatî vedîtin, çareser bikin. Ev dê bibe peywirek "lîstik" ku sê serîlêdanan pêk tîne, ku her yek ji wan navek domainek diyar dike: "app1", "app2", "app3".

Di hundurê her serîlêdanê de, pêvajoyên karsaziyê têne destpêkirin ku bi navgîniya otobusa entegrasyonê dest bi "lîstina topê" dikin. Peyamên bi navê "Ball" dê wekî topek tevbigerin.

Rêzên lîstikê:

  • lîstikvanê yekem destpêker e. Ew lîstikvanên din vedixwîne lîstikê, lîstikê dest pê dike û dikare her dem biqedîne;
  • lîstikvanên din beşdarbûna xwe di lîstikê de eşkere dikin, hev û lîstikvanê yekem "nas bikin";
  • piştî wergirtina gogê, lîstikvan lîstikvanek din yê beşdar hildibijêre û gogê jê re derbas dike. Hejmara giştî ya veguhestinê tê hesibandin;
  • Her lîstikvanek xwediyê "enerjiyê" ye ku bi her derbaskirina topê ji hêla wî lîstikvan ve kêm dibe. Dema ku enerjî diqede, lîstikvan dev ji lîstikê berdide, îstifakirina xwe radigihîne;
  • ger lîstikvan bi tenê bimîne, yekser derketina xwe radigihîne;
  • Dema ku hemî lîstikvan têne hilweşandin, lîstikvanê yekem lîstikê xilas dike. Ger ew zû ji lîstikê derkeve, ew dimîne ku lîstikê bişopîne da ku wê temam bike.

Ji bo çareserkirina vê pirsgirêkê, ez ê DSL-ya xwe ji bo pêvajoyên karsaziyê bikar bînim, ku destûrê dide me ku em mantiqê li Kotlin bi hûrgulî, bi hindiktirîn boilerplate vebêjin.

Pêvajoya karsaziya lîstikvanê yekem (aka destpêkerê lîstikê) dê di serîlêdana app1 de bixebite:

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

Digel pêkanîna mantiqa karsaziyê, koda jorîn dikare modelek pêvajoyek karsaziyê çêbike, ku dikare di forma diagramê de were xuyang kirin. Me hîna dîmenderê bicîh neaniye, ji ber vê yekê me neçar ma ku demek hindik bi xêzkirinê derbas bikin (li vir min di derheqê karanîna dergehan de nîşana BPMN hinekî hêsan kir da ku hevrêziya diagramê bi koda jêrîn re baştir bike):

entegrasyona şêwaza BPM

app2 dê pêvajoya karsaziya lîstikvanê din bihewîne:

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

Dîyagram:

entegrasyona şêwaza BPM

Di serîlêdana app3-ê de em ê lîstikvanek bi tevgerek hinekî cûda çêkin: li şûna ku lîstikvanê din bi rengek bêhemdî hilbijêrin, ew ê li gorî algorîtmaya dor-robin tevbigere:

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

Wekî din, tevgera lîstikvan ji ya berê cûda nabe, ji ber vê yekê diagram nayê guhertin.

Naha em hewceyê ceribandinek e ku em van hemî bimeşînin. Ez ê tenê koda testê bi xwe bidim, da ku gotarê bi kazan re nehêlim (bi rastî, min hawîrdora ceribandinê ya ku berê hatî afirandin bikar anî da ku yekbûna pêvajoyên karsaziyê yên din ceriband):

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

Ka em testê bimeşînin û li têketinê binihêrin:

derketina konsolê

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

Ji van hemûyan em dikarin çend encamên girîng derxînin:

  • bi amûrên pêwîst re, pêşdebirên serîlêdanê dikarin têkiliyên entegrasyonê di navbera serlêdanan de bêyî qutkirina mantiqa karsaziyê biafirînin;
  • tevliheviya peywirek entegrasyonê ya ku jêhatîyên endezyariyê hewce dike dikare di çarçovê de were veşartin heke ev di destpêkê de di mîmariya çarçovê de be. Zehmetiya pirsgirêkê nikare veşêre, ji ber vê yekê çareseriya pirsgirêkek dijwar di kodê de dê wusa xuya bike;
  • Dema ku mantiqa entegrasyonê pêş dixin, pêdivî ye ku meriv lihevhatina dawî û nebûna xêzkirina guhertinên di rewşa hemî beşdarên entegrasyonê de li ber çavan were girtin. Ev me mecbûr dike ku em mantiqê tevlihev bikin da ku ew ji rêza ku bûyerên derve tê de diqewimin bêhesiyar bikin. Di mînaka me de, lîstikvan piştî ku derketina xwe ji lîstikê ragihand, neçar dimîne ku beşdarî lîstikê bibe: lîstikvanên din dê berdewam bikin ku topê ji wî re derbas bikin heya ku agahdariya der barê derketina wî de bigihîje û ji hêla hemî beşdaran ve were pêvajo kirin. Ev mantiq ji qaîdeyên lîstikê dernakeve û di çarçoveya mîmariya hilbijartî de çareseriyek lihevkirinê ye.

Piştre, em ê li ser cûrbecûr tevliheviyên çareseriyê, lihevkirin û xalên din biaxivin.

Hemî peyam di yek rêzê de ne

Hemî serîlêdanên yekbûyî bi yek otobusek entegrasyonê re dixebitin, ku di forma brokerek derveyî, yek BPMQueue ji bo peyaman û yek mijarek BPMTopic ji bo nîşanan (bûyer) tê pêşkêş kirin. Danîna hemî peyaman di yek rêzê de bi xwe lihevhatinek e. Di asta mantiqa karsaziyê de, hûn naha dikarin bi qasî ku hûn dixwazin gelek celebên peyamên nû destnîşan bikin bêyî ku hûn di strûktûra pergalê de guhartinan bikin. Ev sadebûnek girîng e, lê ew hin xetereyan hildigire, ku di çarçoveya karên me yên tîpîk de ji me re ew qas girîng xuya nedikir.

entegrasyona şêwaza BPM

Lêbelê, li vir hûrguliyek heye: her serîlêdan peyamên "xwe" ji rêza li ber deriyê, bi navê domaina xwe fîlter dike. Heke hûn hewce ne ku "çarçoveya dîtinê" ya sînyalê bi yek serîlêdanê ve sînordar bikin, domain dikare di nîşanan de jî were destnîşan kirin. Pêdivî ye ku ev karûbarê otobusê zêde bike, lê mentîqa karsaziyê naha divê bi navên domainê re bixebite: ji bo navnîşana peyaman - mecbûrî, ji bo nîşanan - xwestî ye.

Paqijkirina pêbaweriya otobusê ya entegrasyonê

Bawerî ji çend xalan pêk tê:

  • Brokera peyamê ya hilbijartî hêmanek krîtîk a mîmariyê ye û xalek têkçûnek yekane ye: Pêdivî ye ku ew bi têra xwe tolerasyona xeletiyê be. Pêdivî ye ku hûn tenê pêkanînên dem-ceribandinî, bi piştgirîyek baş û civatek mezin bikar bînin;
  • Pêdivî ye ku meriv hebûna bilind a brokera peyamê were misoger kirin, ji bo vê yekê divê ew bi fizîkî ji sepanên yekbûyî were veqetandin (berdestbûna zêde ya serîlêdanên bi mantiqa karsaziya sepandî pir dijwartir û bihatir e ku were piştrast kirin);
  • broker mecbûr e ku "qet nebe carekê" garantiyên radestkirinê peyda bike. Ev ji bo xebata pêbawer a otobusa entegrasyonê hewcedariyek mecbûrî ye. Ne hewce ye ku garantiyên asta "temam carekê": pêvajoyên karsaziyê, bi gelemperî, ji hatina dubare ya peyaman an bûyeran re ne hesas in, û di karên taybetî de ku ev girîng e, hêsantir e ku meriv kontrolên din li karsaziyê zêde bike. mantiq ji bikaranîna berdewam garantiyên pir "biha" ";
  • şandina peyam û îşaretan divê di nav danûstendinek giştî de digel guhertinên di rewşa pêvajoyên karsaziyê û daneyên domainê de beşdar bibin. Vebijêrkek bijartî dê bikar bînin nimûne Transactional Outbox, lê ew ê di databasê de tabloyek zêde û dubarekerek hewce bike. Di serîlêdanên JEE-yê de, ev dikare bi karanîna rêveberek JTA-ya herêmî ve were hêsan kirin, lê pêwendiya bi brokera hilbijartî re pêdivî ye ku karibe di nav de bixebite. XA;
  • Gerînendekarên peyam û bûyeran jî divê bi danûstendinek ku rewşa pêvajoyek karsaziyê diguhezîne re bixebitin: heke danûstendinek weha paşve were paşve xistin, wê hingê divê wergirtina peyamê were betal kirin;
  • peyamên ku ji ber xeletiyan nehatine radest kirin divê di depoyek cihê de bêne hilanîn D.L.Q. (Dîroka Nameya Mirî). Ji bo vê mebestê, me mîkroxizmetek platformek cihê afirand ku peyamên weha di hilanîna xwe de hilîne, wan ji hêla taybetmendiyan ve (ji bo komkirin û lêgerîna bilez) nîşan dide, û API-yek ji bo dîtinê, ji nû ve şandina navnîşana mebestê, û jêbirina peyaman eşkere dike. Rêvebirên pergalê dikarin bi navbeynkariya xweya webê bi vê karûbarê re bixebitin;
  • di mîhengên brokerê de, hûn hewce ne ku hejmara dubareyên radestkirinê û derengbûnên di navbera radestkirinê de rast bikin da ku îhtîmala ketina peyaman di DLQ de kêm bikin (hesabkirina pîvanên çêtirîn hema hema ne gengaz e, lê hûn dikarin bi awayekî empirîkî tevbigerin û di dema xebatê de wan rast bikin. );
  • Pêdivî ye ku firotgeha DLQ bi domdarî were şopandin, û pergala çavdêriyê divê rêvebirên pergalê hişyar bike da ku gava ku peyamên negihîştî çêbibin, ew dikarin bi lez û bez bersiv bidin. Ev ê "herêma bi bandor" a têkçûn an xeletiyek mantiqa karsaziyê kêm bike;
  • otobusa entegrasyonê divê ji nebûna demkî ya serîlêdanan re nehesas be: Divê aboneyên mijarekê domdar bin, û navê domainê ya serîlêdanê yekta be, da ku dema ku serîlêdan tune be, kesek din hewl nede ku peyamên xwe ji serîlêdanê bişopîne. mar.

Paqijkirina ewlehiya tîrêjê ya mantiqa karsaziyê

Heman mînakek pêvajoyek karsaziyê dikare bi yekcarî çend peyam û bûyeran werbigire, ku pêvajoykirina wan dê paralel dest pê bike. Di heman demê de, ji bo pêşdebirek serîlêdanê, divê her tişt sade û ewledar be.

Mantiqa karsaziya pêvajoyek her bûyerek derveyî ku bandorê li wê pêvajoya karsaziyê bi ferdî dike pêvajoyê dike. Bûyerên weha dikarin bibin:

  • destpêkirina mînakek pêvajoya karsaziyê;
  • çalakiya bikarhêner bi çalakiya di nav pêvajoyek karsaziyê de têkildar e;
  • wergirtina peyamek an îşaretek ku pêvajoyek pêvajoyek karsaziyê jê re tê pejirandin;
  • destpêkirina demjimêrek ku ji hêla mînakek pêvajoya karsaziyê ve hatî destnîşan kirin;
  • çalakiya kontrolkirina bi API (mînak, qutkirina pêvajoyê).

Her bûyerek weha dikare rewşa mînakek pêvajoyek karsaziyê biguhezîne: dibe ku hin çalakî bi dawî bibin û yên din dest pê bikin, û dibe ku nirxên taybetmendiyên domdar biguhezin. Girtina her çalakiyê dibe ku bibe sedema çalakkirina yek an çend ji çalakiyên jêrîn. Ew, di encamê de, dikarin li benda bûyerên din rawestin an jî, heke ji wan re daneyên zêde ne hewce be, dikarin di heman danûstendinê de temam bikin. Berî girtina danûstendinê, rewşa nû ya pêvajoya karsaziyê di databasê de tê hilanîn, ku ew ê li bendê bimîne ku bûyera derveyî ya din çêbibe.

Daneyên pêvajoya karsaziya domdar ên ku di databasek pêwendiyê de têne hilanîn xalek pir hêsan e ji bo hevdengkirina pêvajoyê heke hûn JI BO NÛZEXANÊ SELECT bikar bînin. Ger yek danûstendinek karibe rewşa pêvajoyek karsaziyê ji bingeha guhartina wê werbigire, wê hingê ti danûstendinek din a paralel dê nikaribe heman rewşê ji bo guhertinek din bidest bixe, û piştî temamkirina danûstendina yekem, ya duyemîn garantî ye ku hûn dewleta ku berê hatî guheztin bistînin.

Bi karanîna kilîdên pessimîst li ser milê DBMS, em hemî hewcedariyên pêwîst pêk tînin TIRŞ, û di heman demê de şiyana pîvandina serîlêdanê bi mantiqa karsaziyê bi zêdekirina hejmara bûyerên xebitandinê digire.

Lêbelê, qeflên pessimîst me bi xitimanan tehdîd dikin, ku tê vê wateyê ku JI BO NÛVEKIRINÊ HILBIJARTIN divê hîn jî bi hin demek maqûl ve were sînordar kirin ji ber ku di mantiqa karsaziyê de li ser hin dozên berbiçav diqewimin.

Pirsgirêkek din hevdemkirina destpêkirina pêvajoyek karsaziyê ye. Digel ku mînakek pêvajoyek karsaziyê tune, di databasê de dewletek tune, ji ber vê yekê rêbaza diyarkirî dê nexebite. Ger hûn hewce ne ku yektaya mînakek pêvajoyek karsaziyê di çarçoveyek taybetî de piştrast bikin, wê hingê hûn ê hewceyê cûreyek tişta hevdemkirinê ya ku bi çîna pêvajoyê û qada têkildar ve girêdayî ye hewce bikin. Ji bo çareserkirina vê pirsgirêkê, em mekanîzmayek girtina cihêreng bikar tînin ku destûrê dide me ku em bi karûbarek derveyî ve li ser çavkaniyek kêfî ya ku ji hêla mifteyê ve di forma URI-yê de hatî destnîşan kirin kilît bikin.

Di mînakên me de, pêvajoya karsaziya InitialPlayer daxuyaniyek dihewîne

uniqueConstraint = UniqueConstraints.singleton

Ji ber vê yekê, têketin di derbarê girtin û berdana kilîtkirina mifteya têkildar de peyam hene. Ji bo pêvajoyên karsaziyê yên din peyamên weha tune: yekaneConstraint nehatiye danîn.

Pirsgirêkên pêvajoyên karsaziyê yên bi dewleta domdar

Carinan hebûna dewletek domdar ne tenê dibe alîkar, lê di heman demê de bi rastî pêşkeftinê jî asteng dike.
Pirsgirêkan dest pê dikin dema ku pêdivî ye ku guhartin di mantiqa karsaziyê û / an modela pêvajoya karsaziyê de bêne çêkirin. Ne her guhertinek wusa bi rewşa kevin a pêvajoyên karsaziyê re hevaheng e. Ger di databasê de gelek mînakên zindî hebin, wê hingê çêkirina guheztinên ne lihevhatî dikare bibe sedema gelek tengasiyan, ku em pir caran dema ku jBPM bikar tînin rastî wan tê.

Bi kûrahiya guhertinan ve girêdayî, hûn dikarin bi du awayan tevbigerin:

  1. cureyek pêvajoya karsaziya nû biafirînin da ku li ya kevin guheztinên ne lihevhatî çênekin, û dema destpêkirina mînakên nû li şûna ya kevin bikar bînin. Kopiyên kevn dê "wek berê" bixebitin;
  2. dema nûvekirina mantiqa karsaziyê, rewşa domdar a pêvajoyên karsaziyê koçber bikin.

Awayê yekem hêsantir e, lê sînor û dezawantajên wê hene, mînakî:

  • dubarekirina mantiqa karsaziyê di gelek modelên pêvajoya karsaziyê de, zêdekirina qebareya mantiqa karsaziyê;
  • Bi gelemperî veguherînek tavilê ji bo mantiqa karsaziya nû hewce ye (di warê karên entegrasyonê de - hema hema her gav);
  • pêşdebir nizane di kîjan xalê de modelên kevnar dikarin werin jêbirin.

Di pratîkê de em herdu rêbazan bikar tînin, lê ji bo ku jiyana xwe hêsantir bikin çend biryar dane:

  • Di databasê de, rewşa domdar a pêvajoyek karsaziyê bi rengek hêsan tête xwendin û bi hêsanî tête hilanîn: di nav rêzek formata JSON de. Ev dihêle ku koçberî hem di hundurê serîlêdanê de û hem jî li derve bêne kirin. Wekî çareya paşîn, hûn dikarin wê bi destan rast bikin (bi taybetî di pêşkeftinê de di dema debuggkirinê de kêrhatî ye);
  • mantiqa karsaziya entegrasyonê navên pêvajoyên karsaziyê bikar nayîne, ji ber vê yekê di her kêliyê de gengaz e ku meriv pêkanîna yek ji pêvajoyên beşdar bi navek nû bi navek nû veguherîne (mînak, "InitialPlayerV2"). Girêdan bi navên peyam û sînyalan pêk tê;
  • modela pêvajoyê jimareyek guhertoyek heye, ku heke em li vê modelê guheztinên nelihev bikin em vê hejmarê zêde dikin, û ev hejmar digel rewşa mînaka pêvajoyê tê tomar kirin;
  • rewşa domdar a pêvajoyê pêşî ji databasê di nav modelek tiştek hêsan de tê xwendin, ku prosedûra koçberiyê dikare pê re bixebite ger jimareya guhertoya modelê were guhertin;
  • prosedûra koçberiyê li kêleka mantiqa karsaziyê tê danîn û ji bo her mînakek pêvajoya karsaziyê di dema nûvekirina wê ji databasê de "tebel" tê gotin;
  • heke hûn hewce ne ku rewşa hemî pêvajoyên pêvajoyê bi lez û hevdemî biguhezînin, çareseriyên koçberiya databasa klasîk bêtir têne bikar anîn, lê divê hûn bi JSON re bixebitin.

Ma hûn ji bo pêvajoyên karsaziyê çarçoveyek din hewce ne?

Çareseriyên ku di gotarê de hatine destnîşan kirin rê da me ku em jiyana xwe bi girîngî hêsan bikin, rêza pirsgirêkên ku di asta pêşkeftina serîlêdanê de têne çareser kirin berfireh bikin, û ramana veqetandina mantiqa karsaziyê di nav mîkroxizmetan de balkêştir bikin. Ji bo gihîştina vê yekê, gelek kar hate kirin, çarçoveyek pir "sivik" ji bo pêvajoyên karsaziyê hate afirandin, û her weha pêkhateyên karûbarê ji bo çareserkirina pirsgirêkên naskirî di çarçoweya pirfirehî ya pirsgirêkên serîlêdanê de. Daxwaza me heye ku em van encaman parve bikin û pêşkeftina pêkhateyên hevpar di bin destûrnameyek belaş de vekin. Ev ê hin hewldan û dem hewce bike. Fêmkirina daxwaza çareseriyên bi vî rengî dikare ji bo me bibe teşwîqek zêde. Di gotara pêşniyarê de, pir hindik bala xwe dide kapasîteyên çarçoweyê bixwe, lê hin ji wan ji mînakên pêşkêşkirî têne xuyang kirin. Ger em çarçoveya xwe biweşînin, dê gotarek cuda jê re were veqetandin. Di vê navberê de, em ê spasdar bin ger hûn bi bersivdana pirsê re hinekî bertek bihêlin:

Tenê bikarhênerên qeydkirî dikarin beşdarî anketê bibin. Têketinji kerema xwe.

Ma hûn ji bo pêvajoyên karsaziyê çarçoveyek din hewce ne?

  • 18,8%Belê, ez ji zû ve li tiştekî weha digerim

  • 12,5%Ez meraq dikim ku di derheqê pêkanîna we de bêtir fêr bibim, dibe ku ew kêrhatî be2

  • 6,2%Em yek ji çarçoveyek heyî bikar tînin, lê li şûna 1 difikirin

  • 18,8%Em yek ji çarçoveyên heyî bikar tînin, her tişt baş e3

  • 18,8%em bê çarçove3 îdare dikin

  • 25,0%ya xwe binivîse4

16 bikarhêneran deng dan. 7 bikarhêner jî betal bûn.

Source: www.habr.com

Add a comment