Gure enpresa ERP mailako software-soluzioen garapenean espezializatuta dago, eta horien zati handiena negozio-logika eta dokumentu-fluxu handia duten transakzio-sistemek hartzen dute EDMSa. Gure produktuen egungo bertsioak JavaEE teknologietan oinarritzen dira, baina mikrozerbitzuekin ere aktiboki esperimentatzen ari gara. Soluzio horien arlorik problematikoenetako bat ondoko domeinuetako hainbat azpisistemaren integrazioa da. Integrazio arazoek buruhauste handia eman digute beti, erabiltzen ditugun arkitektura-estiloak, teknologia-pilak eta markoak kontuan hartu gabe, baina azkenaldian aurrerapausoak eman dira horrelako arazoak konpontzen.
Zure arreta jartzen dizudan artikuluan NPO Kristak izendatutako eremuan duen esperientzia eta ikerketa arkitektonikoaz hitz egingo dut. Era berean, aplikazioen garatzaile baten ikuspegitik integrazio-arazo baten irtenbide sinple baten adibide bat ikusiko dugu eta sinpletasun horren atzean zer ezkutatzen den ezagutuko dugu.
Erantzukizuna
Artikuluan deskribatzen diren irtenbide arkitektonikoak eta teknikoak nik proposatzen ditut zeregin zehatzen testuinguruko esperientzia pertsonalean oinarrituta. Irtenbide hauek ez dute unibertsalak direnik eta baliteke beste erabilera-baldintzetan optimoak ez izatea.
Zer zerikusi du BPM-k?
Galdera honi erantzuteko, gure soluzioen aplikatutako arazoen zehaztasunetan apur bat sakondu behar dugu. Gure transakzio-sistema tipikoko negozio-logikaren zati nagusia datuak datu-basean sartzea da erabiltzaile-interfazeen bidez, datu horien egiaztapen eskuz eta automatizatua, lan-fluxu batzuen bidez egitea, beste sistema / datu base analitikoa / artxibo batean argitaratzea, txostenak sortzea. . Horrela, bezeroentzako sistemaren funtsezko funtzioa beren barneko negozio-prozesuen automatizazioa da.
Erosotasunerako, komunikazioan "dokumentu" terminoa erabiltzen dugu lan-fluxu jakin bat "lotu" daitekeen gako komun batek batutako datu multzo baten abstrakzio gisa.
Baina zer gertatzen da integrazio logikarekin? Azken finean, integrazio-zeregina sistemaren arkitekturak sortzen du, eta zatitan "moztu" egiten da EZ bezeroak eskatuta, baizik eta faktore guztiz desberdinen eraginpean:
Conwayren legearen menpe;
aurretik beste produktu batzuetarako garatutako azpisistemak berrerabiltzearen ondorioz;
arkitektoaren erabakiz, baldintza ez-funtzionaletan oinarrituta.
Tentazio handia dago integrazio-logika lan-fluxu nagusiaren negozio-logikatik bereizteko, negozio-logika integrazio-artefaktuekin ez kutsatzeko eta aplikazioen garatzailea sistemaren paisaia arkitektonikoaren berezitasunetan sakontzeko beharra arintzeko. Ikuspegi honek abantaila ugari ditu, baina praktikak bere eraginkortasunik eza erakusten du:
integrazio-arazoak konpontzea normalean dei sinkronikoen moduan aukerarik sinpleenetara itzuliko da lan-fluxu nagusiaren ezarpenean luzapen-puntu mugatuak direla eta (integrazio sinkronikoaren desabantailak behean eztabaidatzen dira);
integrazio-artefaktuak negozioaren oinarrizko logika sartzen dira oraindik beste azpisistema baten feedbacka behar denean;
aplikazioaren garatzaileak integrazioa alde batera uzten du eta erraz hautsi dezake lan-fluxua aldatuz;
sistemak osotasun bakarra izateari uzten dio erabiltzailearen ikuspuntutik, azpisistemen arteko βjunturakβ nabaritzen dira eta erabiltzaileen eragiketa erredundanteak agertzen dira, azpisistema batetik bestera datuak transferitzeari hasiera emanez.
Beste ikuspegi bat integrazio-interakzioak negozioaren oinarrizko logikaren eta lan-fluxuaren osagai gisa hartzea da. Aplikazioen garatzaileen kualifikazioak gora egitea saihesteko, integrazio-interakzio berriak sortzea erraza eta esfortzurik gabea izan behar da, irtenbide bat aukeratzeko aukera minimoarekin. Hori egitea dirudiena baino zailagoa da: tresnak nahikoa indartsua izan behar du erabiltzaileari bere erabilerarako behar dituen aukera ugari eskaintzeko, "oinean tiro egiten" utzi gabe. Ingeniari batek integrazio-zereginen testuinguruan erantzun behar dituen galdera asko daude, baina aplikazioen garatzaileak bere eguneroko lanean pentsatu behar ez dituenak: transakzioen mugak, koherentzia, atomizazioa, segurtasuna, eskalatzea, karga eta baliabideen banaketa, bideratzea, marshaling, banaketa- eta aldatze-testuinguruak, etab. Beharrezkoa da aplikazio-garatzaileei irtenbide nahiko soil-txantiloiak eskaintzea, non galdera horien erantzunak dagoeneko ezkutatuta dauden. Txantiloi hauek nahiko seguruak izan behar dute: negozio-logika oso maiz aldatzen da, eta horrek akatsak sartzeko arriskua areagotzen du, akatsen kostua nahiko maila baxuan mantendu behar da.
Baina zer zerikusi du BPM-k? Lan-fluxua ezartzeko aukera asko daude...
Izan ere, negozio-prozesuen beste inplementazio bat oso ezaguna da gure soluzioetan - egoera trantsizio-diagrama baten definizio deklaratiboaren bidez eta kudeatzaileak trantsizioetarako negozio-logikarekin lotuz. Kasu honetan, negozio-prozesuan "dokumentuaren" egungo posizioa zehazten duen egoera "dokumentuaren" beraren atributua da.
Horrelako itxura du prozesuak proiektu baten hasieran
Inplementazio honen ospea negozio-prozesu linealak sortzeko sinpletasun eta abiadura erlatiboari zor zaio. Hala ere, software-sistemak etengabe konplexuagoak diren heinean, negozio-prozesuaren zati automatizatua hazi eta konplexuagoa bihurtzen da. Deskonposizioa, prozesuen zatiak berrerabiltzea eta adarkatze prozesuak behar dira, adar bakoitza paraleloan exekutatu dadin. Baldintza horietan, tresna deseroso bihurtzen da, eta egoera-trantsizio-diagramak informazio-edukia galtzen du (integrazio-interakzioak ez dira diagraman batere islatzen).
Hau da prozesuak eskakizunak argitzeko hainbat iterazioren ondoren.
Egoera horretatik ateratzeko bidea motorra integratzea izan zen jBPM negozio-prozesu konplexuenak dituzten produktu batzuetan. Epe laburrean, irtenbide honek nolabaiteko arrakasta izan zuen: negozio-prozesu konplexuak ezartzea posible izan zen, idazkeran diagrama nahiko informatiboa eta garrantzitsua mantenduz. BPMN2.
Negozio prozesu konplexu baten zati txiki bat
Epe luzera, irtenbideak ez zituen itxaropenak bete: tresna bisualen bidez negozio-prozesuak sortzeko lan intentsitate handiak ez zuen produktibitate-adierazle onargarriak lortzea ahalbidetzen, eta tresna bera garatzaileen artean gustukoenetako bat bihurtu zen. Motorraren barne egiturari buruzko kexak ere egon ziren, eta horrek βadabakiβ eta βmakuluβ asko agertzea ekarri zuen.
jBPM erabiltzearen alderdi positibo nagusia negozio prozesu-instantzia baten egoera iraunkorra izatearen onuren eta kalteen kontzientzia izan zen. Era berean, prozesu-ikuspegia erabiltzeko aukera ikusi genuen aplikazio ezberdinen artean integrazio-protokolo konplexuak ezartzeko seinaleen eta mezuen bidez interakzio asinkronoak erabiliz. Egoera iraunkor baten presentzia funtsezkoa da horretan.
Aurrekoa kontuan hartuta, honakoa ondoriozta dezakegu: BPM estiloko prozesuen ikuspegiari esker, zeregin sorta zabala ebazteko aukera ematen digu gero eta konplexuagoak diren negozio-prozesuak automatizatzeko, prozesu horietan integrazio-jarduerak harmoniatsu egokitzeko eta inplementatutako prozesua idazkera egoki batean bisualki bistaratzeko gaitasuna mantentzeko.
Dei sinkronikoen desabantailak integrazio eredu gisa
Integrazio sinkronikoa blokeo-dei errazena da. Azpisistema batek zerbitzariaren alde egiten du eta APIa eskatzen duen metodoarekin erakusten du. Beste azpisistema batek bezeroaren alde egiten du eta une egokian dei bat egiten du eta emaitzaren zain geratzen da. Sistemaren arkitekturaren arabera, bezeroaren eta zerbitzariaren aldeak aplikazio eta prozesu berean egon daitezke, edo desberdinetan. Bigarren kasuan, RPC inplementazioren bat aplikatu eta parametroen eta deiaren emaitzaren marshalling eman behar duzu.
Integrazio eredu honek desabantaila multzo nahiko handia du, baina praktikan oso erabilia da bere sinpletasuna dela eta. Inplementazio-abiadurak liluratu eta behin eta berriro erabiltzera behartzen zaitu epe larrien aurrean, irtenbidea zor tekniko gisa erregistratuz. Baina esperientziarik gabeko garatzaileek inkontzienteki erabiltzen dutela ere gertatzen da, ondorio negatiboak konturatu gabe.
Azpisistemen konektibitatearen gehikuntzarik nabarmenenaz gain, transakzio "hazi" eta "luzatzeko" arazo ez hain nabariak ere badaude. Izan ere, negozio-logikak aldaketa batzuk egiten baditu, orduan transakzioak ezin dira saihestu, eta transakzioek, aldi berean, aldaketa horiek eragindako aplikazio-baliabide batzuk blokeatzen dituzte. Hau da, azpisistema batek bestearen erantzunaren zain egon arte, ezin izango du transakzioa burutu eta blokeoak kendu. Horrek nabarmen handitzen du hainbat ondorio izateko arriskua:
Sistemaren erantzuna galtzen da, erabiltzaileek denbora luzez itxaron egiten dute kontsulten erantzunak;
zerbitzariak, oro har, erabiltzaileen eskaerei erantzutea uzten du gainezka dagoen hari multzoa dela eta: hari gehienak transakzio batek okupatutako baliabide batean blokeatuta daude;
Blokeoak agertzen hasten dira: haien agerraldiaren probabilitatea transakzioen iraupenaren, negozio logikaren eta transakzioan parte hartzen duten blokeoen araberakoa da;
transakzio denbora-muga akatsak agertzen dira;
zerbitzariak "huts" egiten du OutOfMemory-rekin, zereginak datu-kopuru handiak prozesatu eta aldatzea eskatzen badu, eta integrazio sinkronoak egoteak oso zaila egiten du prozesatzea transakzio "arinagoetan" banatzea.
Arkitekturaren ikuspuntutik, integrazioan deiak blokeatzeak erabiltzeak azpisistema indibidualen kalitatearen gaineko kontrola galtzea dakar: ezinezkoa da azpisistema baten xede-kalitate-adierazleak beste azpisistema bateko kalitate-adierazleetatik isolatuta bermatzea. Azpisistemak talde ezberdinek garatzen badituzte, arazo handia da.
Gauzak are interesgarriagoak dira integratzen ari diren azpisistemak aplikazio ezberdinetan badaude eta bi aldeetatik aldaketa sinkronoak egin behar badituzu. Nola ziurtatu aldaketa horien transakzionaltasuna?
Aldaketak transakzio bereizietan egiten badira, salbuespenen kudeaketa eta konpentsazio fidagarriak eman beharko dituzu, eta horrek integrazio sinkronikoen onura nagusia ezabatzen du: sinpletasuna.
Banatutako transakzioak ere etortzen zaizkigu burura, baina ez ditugu gure soluzioetan erabiltzen: zaila da fidagarritasuna ziurtatzea.
"Saga" transakzio arazoaren irtenbide gisa
Mikrozerbitzuen ospea gero eta handiagoarekin, eskaria Saga Eredua.
Eredu honek ezin hobeto konpontzen ditu lehen aipatutako transakzio luzeen arazoak, eta sistemaren egoera kudeatzeko gaitasunak ere zabaltzen ditu negozio-logikaren aldetik: huts egin duen transakzio baten ondoriozko kalte-ordainak baliteke sistema bere jatorrizko egoerara itzultzea, baina ematen du. datuak prozesatzeko bide alternatibo bat. Horrek, gainera, arrakastaz amaitutako datuak prozesatzeko urratsak errepikatzea saihesteko aukera ematen du prozesua amaiera "onera" eramaten saiatzean.
Interesgarria da sistema monolitikoetan eredu hau garrantzitsua da akoplatutako azpisistemen baxuen integrazioari dagokionez eta epe luzeko transakzioek eta dagozkien baliabideen blokeoek eragindako ondorio negatiboak ikusten direnean.
BPM estiloko gure negozio prozesuei dagokienez, oso erraza da "Sagas" ezartzea: "Saga"ren urrats indibidualak negozio-prozesuaren barruan jarduera gisa zehaztu daitezke, eta negozio-prozesuaren egoera iraunkorra ere. "Saga"ren barne-egoera zehazten du. Hau da, ez dugu koordinazio mekanismo gehigarririk behar. Behar duzun guztia garraio gisa "gutxienez behin" bermeak onartzen dituen mezu-artekari bat da.
Baina irtenbide honek bere "prezioa" ere badu:
negozio-logika konplexuagoa bihurtzen da: kalte-ordainak landu behar dira;
beharrezkoa izango da koherentzia osoa alde batera utzi, sistema monolitikoetarako bereziki sentikorra izan daitekeena;
Arkitektura apur bat konplikatuagoa bihurtzen da, eta mezu-artekari baten behar gehigarri bat agertzen da;
monitorizazio eta administrazio tresna osagarriak beharko dira (nahiz eta, oro har, ona den: sistemaren zerbitzuaren kalitatea handituko da).
Sistema monolitikoetarako, "Sag" erabiltzearen justifikazioa ez da hain agerikoa. Mikrozerbitzuetarako eta beste SOA batzuetarako, ziurrenik jada broker bat dagoen, eta proiektuaren hasieran koherentzia osoa sakrifikatzen den, eredu hau erabiltzearen onurak desabantailak nabarmen gaindi ditzake, batez ere negozio-logikan API eroso bat badago. maila.
Negozio-logika mikrozerbitzuetan kapsulatzea
Mikrozerbitzuekin esperimentatzen hasi ginenean, arrazoizko galdera bat sortu zen: non kokatu domeinuaren negozio-logika domeinuaren datuen iraupena ziurtatzen duen zerbitzuaren aldean?
Hainbat BPMSren arkitekturari begira, arrazoizkoa dirudi negozio-logika iraunkortasunetik bereiztea: plataforma eta domeinutik independenteak diren mikrozerbitzuen geruza bat sortu, domeinuaren negozio-logika exekutatzeko ingurune eta edukiontzi bat osatzen dutenak, eta domeinuko datuen iraunkortasuna diseinatzea. mikrozerbitzu oso sinple eta arinen geruza bereizia. Negozio-prozesuek kasu honetan iraunkortasun-geruzaren zerbitzuen orkestrazioa egiten dute.
Ikuspegi honek abantaila oso handia du: plataformaren funtzionaltasuna nahi adina handitu dezakezu, eta horri dagokion plataformako mikrozerbitzuen geruza baino ez da "lodi" bihurtuko. Edozein domeinutako negozio-prozesuek plataformaren funtzionaltasun berria berehala erabiltzeko gai dira, eguneratu bezain pronto.
Azterketa zehatzago batek ikuspegi honen desabantaila nabarmenak agerian utzi zituen:
Domeinu askoren negozio-logika aldi berean exekutatzen duen plataforma-zerbitzuak arrisku handiak ditu huts-puntu bakar gisa. Negozio-logikan maiz egiten diren aldaketak sistema osorako hutsegiteak ekartzeko akatsak izateko arriskua areagotzen du;
errendimendu-arazoak: negozio-logikak bere datuekin funtzionatzen du interfaze estu eta motel baten bidez:
datuak berriro ere sare-pilaren bidez banatu eta ponpatu egingo dira;
domeinu-zerbitzu batek negozio-logikak prozesatzeko behar baino datu gehiago emango ditu askotan, zerbitzuaren kanpoko API mailan eskaerak parametrizatzeko gaitasun nahikorik ez duelako;
negozio-logikako hainbat pieza independentek behin eta berriz eska ditzakete datu berdinak prozesatzeko (arazo hau arindu daiteke datuak cachean gordetzen dituzten saio-osagaiak gehituz, baina horrek are gehiago zaildu egiten du arkitektura eta datuen garrantzia eta cachea baliogabetzeko arazoak sortzen ditu);
transakzio arazoak:
egoera iraunkorra duten negozio-prozesuak, plataforma-zerbitzu batek gordetzen dituenak, ez datoz bat domeinuko datuekin, eta ez dago arazo hori konpontzeko modu errazak;
domeinuko datuen blokeoa transakziotik kanpo jartzea: domeinuaren negozio-logikak aldaketak egin behar baditu uneko datuen zuzentasuna egiaztatu ondoren, beharrezkoa da prozesatutako datuen lehiakortasuna aldatzeko aukera baztertzea. Kanpoko datuen blokeoak arazoa konpontzen lagun dezake, baina irtenbide horrek arrisku gehigarriak ditu eta sistemaren fidagarritasun orokorra murrizten du;
zailtasun gehigarriak eguneratzean: kasu batzuetan, iraunkortasun-zerbitzua eta negozio-logika sinkronoki edo sekuentzia zorrotzean eguneratu behar dira.
Azken finean, oinarrietara itzuli behar izan dugu: domeinuaren datuak eta domeinuaren negozio-logika mikrozerbitzu batean kapsulatu. Ikuspegi honek mikrozerbitzu bat sistemaren osagai integral gisa hautematea errazten du eta ez ditu aurreko arazoak sortzen. Hau ere ez da doan ematen:
API estandarizazioa beharrezkoa da negozio-logikarekin (bereziki, erabiltzaile-jarduerak negozio-prozesuen parte gisa eskaintzeko) eta API plataforma-zerbitzuekin elkarreragiteko; arreta handiagoa eskatzen du API aldaketei, aurrera eta atzerako bateragarritasunari;
beharrezkoa da exekuzio-liburutegi osagarriak gehitzea mikrozerbitzu bakoitzaren barruan negozio-logikaren funtzionamendua bermatzeko, eta horrek eskakizun berriak sortzen ditu halako liburutegietarako: arintasuna eta mendekotasun iragankorrak minimoak;
negozio-logikako garatzaileek liburutegien bertsioak kontrolatu behar dituzte: mikrozerbitzu bat denbora luzez amaitu ez bada, ziurrenik liburutegien bertsio zaharkitu bat edukiko du. Ezaugarri berri bat gehitzeko ustekabeko oztopoa izan daiteke eta zerbitzu baten negozio-logika zaharra liburutegien bertsio berrietara migratzea eska dezake bertsioen artean aldaketa bateraezinak egon badira.
Plataforma-zerbitzuen geruza bat ere badago horrelako arkitektura batean, baina geruza honek jada ez du domeinuaren negozio-logika exekutatzeko edukiontzi bat osatzen, bere ingurunea baizik, "plataforma" funtzio osagarriak eskainiz. Geruza hori beharrezkoa da domeinuko mikrozerbitzuen izaera arina mantentzeko ez ezik, kudeaketa zentralizatzeko ere.
Adibidez, negozio-prozesuetako erabiltzaileen jarduerek zereginak sortzen dituzte. Hala ere, zereginekin lan egiten duenean, erabiltzaileak domeinu guztietako zereginak ikusi behar ditu zerrenda orokorrean, hau da, dagokion plataformako atazak erregistratzeko zerbitzu bat egon behar du, domeinuaren negozio-logikatik garbituta. Halako testuinguru batean negozio-logikaren kapsulazioa mantentzea nahiko problematikoa da, eta hau da arkitektura honen beste konpromiso bat.
Negozio-prozesuen integrazioa aplikazioen garatzaile baten begietatik
Arestian esan bezala, aplikazioen garatzaile batek hainbat aplikazioren elkarrekintza ezartzearen ezaugarri tekniko eta ingeniaritzak kendu behar ditu, garapenaren produktibitate ona izan dezan.
Saia gaitezen integrazio arazo zaila konpontzen, artikulurako bereziki asmatua. Hau "joko" zeregina izango da, hiru aplikazio barne hartzen dituena, non haietako bakoitzak domeinu-izen jakin bat definitzen duen: "app1", "app2", "app3".
Aplikazio bakoitzaren barruan, integrazio-busaren bidez "pilotan" hasten diren negozio-prozesuak abiarazten dira. "Pilota" izena duten mezuek pilota gisa jokatuko dute.
Jokoaren arauak:
lehenengo jokalaria abiarazlea da. Beste jokalari batzuk jokora gonbidatzen ditu, jokoa hasten du eta edozein unetan amaitu dezake;
beste jokalariek jokoan parte hartzen dutela adierazten dute, elkar eta lehen jokalaria βezagutuβ;
baloia jaso ondoren, jokalariak parte hartzen duen beste jokalari bat aukeratzen du eta baloia pasatzen dio. Transmisioen kopuru osoa zenbatzen da;
Jokalari bakoitzak "energia" du, jokalari horrek baloiaren pase bakoitzean gutxitzen dena. Energia agortzen denean, jokalariak partida uzten du, bere dimisioa iragarriz;
jokalaria bakarrik geratzen bada, berehala iragartzen du bere irteera;
Jokalari guztiak kanporatzen direnean, lehenengo jokalariak partida amaitutzat emango du. Partida goiz uzten badu, partida jarraitzeko geratzen da hura osatzeko.
Arazo hau konpontzeko, gure DSL negozio-prozesuetarako erabiliko dut, eta horrek Kotlin-en logika trinkoki deskribatzeko aukera ematen digu, gutxieneko boilerplate batekin.
Lehenengo jokalariaren negozio-prozesuak (jokoaren hastapena deitzen dena) app1 aplikazioan funtzionatuko du:
InitialPlayer klasea
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}")
}
Negozio-logika exekutatzeaz gain, goiko kodeak negozio-prozesu baten objektu-eredu bat sor dezake, diagrama moduan ikus daitekeena. Oraindik ez dugu bistaratzailea inplementatu, beraz, denbora pixka bat eman behar izan dugu marrazten (hemen BPMN notazioa apur bat sinplifikatu dut ateen erabilerari dagokionez diagramaren koherentzia hobetzeko beheko kodearekin):
app2-k beste jokalariaren negozio-prozesua barne hartuko du:
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}")
}
Diagrama:
App3 aplikazioan portaera apur bat ezberdina duen jokalari bat egingo dugu: hurrengo jokalaria ausaz hautatu beharrean, round-robin algoritmoaren arabera jokatuko du:
klasea 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}")
}
Bestela, jokalariaren jokabidea ez da aurrekoaren desberdina, beraz, diagrama ez da aldatzen.
Orain hau guztia exekutatzeko proba bat behar dugu. Probaren beraren kodea bakarrik emango dut, artikulua ez nahasteko boilerplate batekin (izan ere, lehenago sortutako proba-ingurunea erabili nuen beste negozio-prozesuen integrazioa probatzeko):
Guzti honetatik hainbat ondorio garrantzitsu atera ditzakegu:
beharrezko tresnekin, aplikazioen garatzaileek aplikazioen arteko integrazio-interakzioak sor ditzakete negozio-logika eten gabe;
ingeniaritza gaitasunak behar dituen integrazio-zeregin baten konplexutasuna esparruaren barruan ezkutatu daiteke, hasiera batean markoaren arkitekturan sartzen bada. Arazo baten zailtasuna ezin da ezkutatu, beraz, kodean arazo zail baten irtenbidea itxura izango du;
Integrazio-logika garatzean, ezinbestekoa da kontuan hartzea koherentzia eventuala eta integrazio-parte-hartzaile guztien egoera-aldaketen linealizagarritasun eza. Horrek logika zailtzera behartzen gaitu, kanpoko gertaerak gertatzen diren ordenaren aurrean sentibera ez izateko. Gure adibidean, jokalaria jokoan parte hartzera behartuta dago jokotik irtetea adierazi ondoren: beste jokalariek baloia pasatzen jarraituko dute, bere irteerari buruzko informazioa parte-hartzaile guztiek heldu eta prozesatu arte. Logika hori ez da joko-arauetatik jarraitzen eta aukeratutako arkitekturaren esparruan konponbide irtenbide bat da.
Jarraian, gure konponbidearen, konpromisoen eta beste puntu batzuen korapilatsuei buruz hitz egingo dugu.
Mezu guztiak ilara batean daude
Aplikazio integratu guztiek integrazio-bus batekin funtzionatzen dute, kanpoko broker baten moduan aurkezten dena, mezuetarako BPMQueue bat eta seinaleetarako (gertaeretarako) gai bat BPMTopic. Mezu guztiak ilara batean jartzea konpromiso bat da. Negozio-logikan, orain nahi adina mezu mota berri sar ditzakezu sistemaren egituran aldaketarik egin gabe. Sinplifikazio nabarmena da hori, baina arrisku batzuk dakartza, gure ohiko zereginen testuinguruan hain esanguratsuak iruditzen ez zitzaizkigunak.
Hala ere, bada hemen sotiltasun bat: aplikazio bakoitzak "bere" mezuak iragazten ditu sarrerako ilaran, bere domeinuaren izenarekin. Domeinua seinaleetan ere zehaztu daiteke seinalearen "ikusgarritasunaren esparrua" aplikazio bakar batera mugatu behar baduzu. Honek autobusaren transmisioa handitu beharko luke, baina negozio-logikak orain domeinu-izenekin funtzionatu behar du: mezuak bideratzeko - derrigorrezkoa, seinaleetarako - desiragarria.
Integrazio Busen fidagarritasuna bermatzea
Fidagarritasuna hainbat puntuk osatzen dute:
Hautatutako mezu-artekaria arkitekturaren osagai kritikoa da eta hutsegite puntu bakarra da: akatsekiko tolerantzia nahikoa izan behar du. Denbora probatutako inplementazioak soilik erabili behar dituzu, laguntza onarekin eta komunitate handi batekin;
beharrezkoa da mezu-artekariaren erabilgarritasun handia bermatzea, eta horretarako fisikoki bereizi behar da aplikazio integratuetatik (aplikaturiko negozio-logika duten aplikazioen erabilgarritasun handia askoz zailagoa eta garestiagoa da ziurtatzea);
artekaria behartuta dago "gutxienez behin" entrega-bermeak ematera. Hau derrigorrezko baldintza da integrazio-busaren funtzionamendu fidagarria izateko. Ez dago "zehazki behin" maila-bermeen beharrik: negozio-prozesuak, oro har, ez dira mezuak edo gertaerak behin eta berriz iristen direnean sentikorrak, eta hori garrantzitsua den zeregin berezietan, errazagoa da negozioari egiaztapen gehigarriak gehitzea. logika "berme nahiko garestiak" etengabe erabiltzea baino;
mezuak eta seinaleak bidaltzeak negozio prozesuen eta domeinuko datuen egoeraren aldaketak dituen transakzio orokor batean parte hartu behar du. Aukera hobetsia eredu bat erabiltzea izango litzateke Irteera-ontzi transakzionala, baina datu-basean taula gehigarri bat eta errepikagailu bat beharko ditu. JEE aplikazioetan, tokiko JTA kudeatzaile bat erabiliz sinplifikatu daiteke, baina hautatutako brokerarekiko konexioak funtzionatzeko gai izan behar du. XA;
Sarrerako mezuen eta gertaeren kudeatzaileek negozio-prozesu baten egoera aldatzen duen transakzio batekin ere lan egin behar dute: transakzio hori atzera botatzen bada, orduan bertan behera utzi behar da mezua jasotzea;
Erroreengatik entregatu ezin izan diren mezuak biltegiratze bereizi batean gorde behar dira D.L.Q. (Hildako gutunen ilara). Horretarako, plataformako mikrozerbitzu bereizi bat sortu dugu, halako mezuak bere biltegian gordetzen dituena, atributuen arabera indexatzen dituena (taldekatze eta bilaketa azkarrak egiteko) eta API bat erakusten duena helmugako helbidera bidaltzeko eta mezuak ezabatzeko. Sistema-administratzaileek zerbitzu honekin lan egin dezakete beren web-interfazearen bidez;
Broker-en ezarpenetan, bidalketa-saioen eta bidalketen arteko atzerapenen kopurua egokitu behar duzu mezuak DLQra sartzeko probabilitatea murrizteko (ia ezinezkoa da parametro optimoak kalkulatzea, baina enpirikoki joka dezakezu eta funtzionatzen ari zaren bitartean doi ditzakezu. );
DLQ biltegia etengabe kontrolatu behar da, eta monitorizazio sistemak sistema-administratzaileei abisatu behar die, entregatu gabeko mezuak gertatzen direnean, ahalik eta azkarren erantzun ditzaten. Horrek hutsegite edo negozio-logikako akats baten "eragindako eremua" murriztuko du;
integrazio-busak ez du izan behar aplikazioen aldi baterako ezaren aurrean: gai baten harpidetzak iraunkorrak izan behar du, eta aplikazioaren domeinu-izena bakarra izan behar da, aplikazioa ez dagoen bitartean, beste norbait ez dadin saiatuko bere mezuak prozesatzen. ilara.
Negozio-logikaren hari segurtasuna bermatzea
Negozio-prozesu baten instantzia berak hainbat mezu eta gertaera jaso ditzake aldi berean, eta horien prozesamendua paraleloan hasiko da. Aldi berean, aplikazioen garatzaile batentzat, dena sinplea eta hari segurua izan behar da.
Prozesu baten negozio-logikak negozio-prozesu horri eragiten dion kanpoko gertaera bakoitza banaka prozesatzen du. Horrelako gertaerak hauek izan daitezke:
negozio-prozesuaren instantzia bat abian jartzea;
erabiltzailearen ekintza negozio-prozesu bateko jarduerarekin lotutakoa;
negozio-prozesuaren instantzia bat harpidetuta dagoen mezu edo seinale bat jasotzea;
negozio-prozesuaren instantzia batek ezarritako tenporizadore bat abiaraztea;
API bidez kontrolatzeko ekintza (adibidez, prozesua etetea).
Gertaera bakoitzak negozio-prozesuaren instantzia baten egoera alda dezake: jarduera batzuk amaitu eta beste batzuk has daitezke, eta propietate iraunkorren balioak alda daitezke. Edozein jarduera ixteak honako jarduera hauetako bat edo gehiago aktibatzea eragin dezake. Horiek, bestalde, beste gertakari batzuen zain egoteari utzi diezaiokete edo, datu gehigarririk behar ez badute, transakzio berean osa dezakete. Transakzioa itxi aurretik, negozio-prozesuaren egoera berria datu-basean gordetzen da, non hurrengo kanpoko gertaera gertatu arte itxarongo den.
Datu-base erlazional batean gordetako negozio-prozesu iraunkorrak prozesatzea sinkronizatzeko oso puntu erosoa da SELECT FOR UPDATE erabiltzen baduzu. Transakzio batek negozio-prozesu baten egoera aldatzeko oinarritik lortu badu, ez da paraleloan beste transakziorik izango egoera bera lortuko beste aldaketa baterako, eta lehenengo transakzioa amaitu ondoren, bigarrena da. dagoeneko aldatutako egoera jasotzea bermatuta.
DBMS aldean blokeo ezkorrak erabiliz, beharrezko baldintza guztiak betetzen ditugu ACID, eta aplikazioa negozio-logikarekin eskalatzeko gaitasunari eusten dio, exekutatzen diren instantzia kopurua handituz.
Hala ere, blokeo ezkorrek blokeoekin mehatxatzen gaituzte, hau da, HAUTATU FOR UPDATE oraindik arrazoizko denbora-muga batera mugatu beharko litzateke negozio-logikako kasu larri batzuetan blokeoak gertatzen badira.
Beste arazo bat negozio prozesu baten hasierako sinkronizazioa da. Negozio prozesu baten instantziarik ez dagoen arren, datu-basean ez dago egoerarik, beraz, deskribatutako metodoak ez du funtzionatuko. Negozio-prozesu-instantzia baten berezitasuna esparru zehatz batean ziurtatu behar baduzu, prozesu-klasearekin eta dagokion esparruarekin lotutako sinkronizazio-objektu bat beharko duzu. Arazo hau konpontzeko, beste blokeo-mekanismo bat erabiltzen dugu, kanpoko zerbitzu baten bidez giltza baten bidez zehaztutako baliabide arbitrario bati blokeoa hartzeko aukera ematen diona.
Gure adibideetan, InitialPlayer negozio-prozesuak deklarazio bat dauka
uniqueConstraint = UniqueConstraints.singleton
Hori dela eta, erregistroak dagokion giltzaren blokeoa hartzeari eta askatzeari buruzko mezuak ditu. Ez dago horrelako mezurik beste negozio prozesuetarako: uniqueConstraint ez dago ezarrita.
Egoera iraunkorreko negozio-prozesuen arazoak
Batzuetan egoera iraunkor bat izateak laguntzen ez ezik, garapena oztopatzen du.
Arazoak negozio-logikan edo/eta negozio-prozesu-ereduan aldaketak egin behar direnean hasten dira. Aldaketa horiek guztiak ez dira bateragarriak negozio prozesuen egoera zaharrarekin. Datu-basean zuzeneko instantzia asko baldin badaude, aldaketa bateraezinak egiteak arazo asko sor ditzake, jBPM erabiltzean askotan aurkitu ditugunak.
Aldaketen sakontasunaren arabera, bi modutara joka dezakezu:
negozio-prozesu mota berri bat sortu zaharrari aldaketa bateraezinak ez egiteko, eta erabili zaharraren ordez instantzia berriak abiarazteko orduan. Kopia zaharrek Β«lehen bezalaΒ» lanean jarraituko dute;
negozio-prozesuen egoera iraunkorra migratu negozio-logika eguneratzean.
Lehenengo bidea sinpleagoa da, baina bere mugak eta desabantailak ditu, adibidez:
negozio-logikaren bikoizketa negozio-prozesu eredu askotan, negozio-logikaren bolumena handituz;
Sarritan negozio-logika berrirako berehalako trantsizioa behar da (integrazio-zereginei dagokienez - ia beti);
garatzaileak ez daki zein puntutan ezabatu daitezkeen eredu zaharkituak.
Praktikan bi ikuspegiak erabiltzen ditugu, baina gure bizitza errazteko hainbat erabaki hartu ditugu:
Datu-basean, negozio-prozesu baten egoera iraunkorra erraz irakurtzeko eta erraz prozesatzeko moduan gordetzen da: JSON formatuko kate batean. Horri esker, migrazioak aplikazio barruan zein kanpoan egin daitezke. Azken aukera gisa, eskuz zuzendu dezakezu (bereziki baliagarria garapenean arazketan);
integrazioko negozio-logikak ez ditu negozio-prozesuen izenak erabiltzen, eta, beraz, edozein unetan posible da parte hartzen duten prozesuetako baten ezarpena beste izen berri batekin ordeztea (adibidez, "InitialPlayerV2"). Lotura mezu eta seinale izenen bidez gertatzen da;
prozesu-ereduak bertsio-zenbaki bat du, eta eredu horretan aldaketa bateraezinak egiten baditugu gehitzen dugu, eta zenbaki hori prozesu-instantziaren egoerarekin batera gordetzen da;
prozesuaren egoera iraunkorra datu-basetik irakurtzen da lehenik objektu-eredu eroso batera, eta migrazio-prozedurak lan egin dezake ereduaren bertsio-zenbakia aldatu bada;
migrazio-prozedura negozio-logikaren ondoan jartzen da eta "alferra" deritzo negozio-prozesuaren instantzia bakoitzerako datu-basetik leheneratzen den unean;
prozesu-instantzia guztien egoera azkar eta sinkronoki migratu behar baduzu, datu-baseen migrazio-soluzio klasikoagoak erabiltzen dira, baina JSONrekin lan egin behar duzu.
Beste esparru bat behar al duzu negozio prozesuetarako?
Artikuluan deskribatutako konponbideek gure bizitza nabarmen erraztu, aplikazioen garapen mailan ebatzitako arazoen sorta zabaltzeko eta negozio-logika mikrozerbitzuetan bereizteko ideia erakargarriagoa izan dadin. Hori lortzeko, lan asko egin zen, negozio-prozesuetarako oso marko βarinaβ sortu zen, baita zerbitzu-osagaiak ere identifikatutako arazoak aplikazio-arazo ugariren testuinguruan konpontzeko. Emaitza hauek partekatzeko eta osagai komunen garapena lizentzia libre baten bidez sarbide irekia izan dadin nahi dugu. Horrek ahalegin eta denbora pixka bat eskatuko du. Horrelako irtenbideen eskaera ulertzea pizgarri gehigarri bat izan daiteke guretzat. Proposatutako artikuluan, oso arreta gutxi jartzen zaie esparruaren beraren gaitasunei, baina horietako batzuk ikusgai daude aurkeztutako adibideetatik. Gure esparrua argitaratzen badugu, aparteko artikulu bat eskainiko zaio. Bitartean, eskertuko genizuke galderari erantzunez iritzi txiki bat uztea:
Erregistratutako erabiltzaileek soilik parte hartu dezakete inkestan. Hasi saioa, mesedez.
Beste esparru bat behar al duzu negozio prozesuetarako?
18,8%Bai, aspalditik nabil horrelako zerbaiten bila
12,5%Zure inplementazioari buruz gehiago jakitea interesatzen zait, baliagarria izan liteke2
6,2%Dauden esparruetako bat erabiltzen dugu, baina ordezkatzea pentsatzen ari gara1
18,8%Dauden esparruetako bat erabiltzen dugu, dena ondo dago3
18,8%markorik gabe kudeatzen dugu3
25,0%idatzi zurea4
16 erabiltzailek eman dute botoa. 7 erabiltzaile abstenitu ziren.