Integreiddio arddull BPM

Integreiddio arddull BPM

Helo, Habr!

Mae ein cwmni'n arbenigo mewn datblygu datrysiadau meddalwedd ERP-dosbarth, lle mae cyfran y llew yn cael ei feddiannu gan systemau trafodion gyda llawer iawn o resymeg busnes a llif gwaith a la EDMS. Mae fersiynau modern o'n cynnyrch yn seiliedig ar dechnolegau JavaEE, ond rydym hefyd wrthi'n arbrofi gyda microwasanaethau. Un o feysydd mwyaf problemus atebion o'r fath yw integreiddio is-systemau amrywiol sy'n gysylltiedig â pharthau cyfagos. Mae tasgau integreiddio bob amser wedi rhoi cur pen enfawr i ni, waeth beth fo'r arddulliau pensaernïol, y staciau technoleg a'r fframweithiau a ddefnyddiwn, ond yn ddiweddar bu cynnydd wrth ddatrys problemau o'r fath.

Yn yr erthygl a ddygwyd i'ch sylw, byddaf yn siarad am brofiad ac ymchwil bensaernïol NPO Krista yn yr ardal ddynodedig. Byddwn hefyd yn ystyried enghraifft o ateb syml i broblem integreiddio o safbwynt datblygwr cais a darganfod beth sydd wedi'i guddio y tu ôl i'r symlrwydd hwn.

Ymwadiad

Mae'r atebion pensaernïol a thechnegol a ddisgrifir yn yr erthygl yn cael eu cynnig gennyf yn seiliedig ar brofiad personol yng nghyd-destun tasgau penodol. Nid yw'r atebion hyn yn honni eu bod yn gyffredinol ac efallai nad ydynt yn optimaidd o dan amodau defnyddio eraill.

Beth sydd gan BPM i'w wneud ag ef?

I ateb y cwestiwn hwn, mae angen inni ymchwilio ychydig i fanylion y problemau cymhwysol yn ein datrysiadau. Prif ran y rhesymeg busnes yn ein system drafodion nodweddiadol yw mewnbynnu data i'r gronfa ddata trwy ryngwynebau defnyddwyr, gwirio'r data hwn â llaw ac yn awtomatig, ei drosglwyddo trwy rywfaint o lif gwaith, ei gyhoeddi i system arall / cronfa ddata ddadansoddol / archif, gan gynhyrchu adroddiadau. Felly, swyddogaeth allweddol y system ar gyfer cwsmeriaid yw awtomeiddio eu prosesau busnes mewnol.

Er hwylustod, rydym yn defnyddio'r term "dogfen" mewn cyfathrebu fel rhywfaint o dynnu set ddata, wedi'i huno gan allwedd gyffredin, y gellir "atodi" llif gwaith penodol iddo.
Ond beth am y rhesymeg integreiddio? Wedi'r cyfan, mae'r dasg o integreiddio yn cael ei gynhyrchu gan bensaernïaeth y system, sy'n cael ei “lifio” i rannau NID ar gais y cwsmer, ond o dan ddylanwad ffactorau cwbl wahanol:

  • dan ddylanwad cyfraith Conwy;
  • o ganlyniad i ailddefnyddio is-systemau a ddatblygwyd yn flaenorol ar gyfer cynhyrchion eraill;
  • fel y penderfynwyd gan y pensaer, yn seiliedig ar ofynion answyddogaethol.

Mae yna demtasiwn mawr i wahanu'r rhesymeg integreiddio oddi wrth resymeg busnes y prif lif gwaith er mwyn peidio â llygru'r rhesymeg fusnes gydag arteffactau integreiddio ac arbed datblygwr y cais rhag gorfod ymchwilio i hynodion tirwedd bensaernïol y system. Mae gan y dull hwn nifer o fanteision, ond mae arfer yn dangos ei aneffeithlonrwydd:

  • mae datrys problemau integreiddio fel arfer yn llithro i lawr i'r opsiynau symlaf ar ffurf galwadau cydamserol oherwydd y pwyntiau ymestyn cyfyngedig wrth weithredu'r prif lif gwaith (mwy ar ddiffygion integreiddio cydamserol isod);
  • mae arteffactau integreiddio yn dal i dreiddio i brif resymeg y busnes pan fo angen adborth o is-system arall;
  • mae datblygwr y cais yn anwybyddu'r integreiddio a gall ei dorri'n hawdd trwy newid y llif gwaith;
  • mae'r system yn peidio â bod yn un cyfanwaith o safbwynt y defnyddiwr, mae "gwythiau" rhwng is-systemau yn dod yn amlwg, mae gweithrediadau defnyddwyr segur yn ymddangos sy'n cychwyn trosglwyddo data o un is-system i'r llall.

Dull arall yw ystyried rhyngweithiadau integreiddio fel rhan annatod o'r rhesymeg busnes craidd a'r llif gwaith. Er mwyn cadw gofynion sgiliau datblygwyr cymwysiadau rhag skyrocketing, dylid creu rhyngweithiadau integreiddio newydd yn hawdd ac yn naturiol, gydag ychydig iawn o opsiynau ar gyfer dewis datrysiad. Mae hyn yn anoddach nag y mae'n edrych: rhaid i'r offeryn fod yn ddigon pwerus i ddarparu'r amrywiaeth angenrheidiol o opsiynau i'r defnyddiwr ar gyfer ei ddefnyddio ac ar yr un pryd peidio â chaniatáu i'w hun gael ei saethu yn y droed. Mae yna lawer o gwestiynau y mae'n rhaid i beiriannydd eu hateb yng nghyd-destun tasgau integreiddio, ond na ddylai datblygwr cais eu hystyried yn eu gwaith beunyddiol: ffiniau trafodion, cysondeb, atomigrwydd, diogelwch, graddio, dosbarthiad llwyth ac adnoddau, llwybro, marsialu, lluosogi a newid cyd-destunau, ac ati Mae angen cynnig templedi penderfyniadau gweddol syml i ddatblygwyr cymwysiadau, lle mae atebion i bob cwestiwn o'r fath eisoes wedi'u cuddio. Dylai’r patrymau hyn fod yn ddigon sicr: mae’r rhesymeg busnes yn newid yn aml iawn, sy’n cynyddu’r risg o gyflwyno gwallau, dylai cost gwallau aros ar lefel weddol isel.

Ond o hyd, beth sydd gan BPM i'w wneud ag ef? Mae yna lawer o opsiynau ar gyfer gweithredu llif gwaith ...
Yn wir, mae gweithrediad arall o brosesau busnes yn boblogaidd iawn yn ein datrysiadau - trwy osodiad datganiadol y diagram pontio cyflwr a chysylltu trinwyr â rhesymeg busnes i'r trawsnewidiadau. Ar yr un pryd, mae'r wladwriaeth sy'n pennu sefyllfa bresennol y "ddogfen" yn y broses fusnes yn nodwedd o'r "ddogfen" ei hun.

Integreiddio arddull BPM
Dyma sut olwg sydd ar y broses ar ddechrau'r prosiect

Mae poblogrwydd gweithrediad o'r fath oherwydd symlrwydd a chyflymder cymharol creu prosesau busnes llinol. Fodd bynnag, wrth i systemau meddalwedd ddod yn fwy cymhleth, mae rhan awtomataidd y broses fusnes yn tyfu ac yn dod yn fwy cymhleth. Mae angen dadelfennu, ailddefnyddio rhannau o brosesau, yn ogystal â phrosesau fforchio fel bod pob cangen yn cael ei gweithredu ochr yn ochr. O dan amodau o'r fath, mae'r offeryn yn dod yn anghyfleus, ac mae'r diagram trawsnewid cyflwr yn colli ei gynnwys gwybodaeth (nid yw rhyngweithiadau integreiddio yn cael eu hadlewyrchu yn y diagram o gwbl).

Integreiddio arddull BPM
Dyma sut olwg sydd ar y broses ar ôl sawl iteriad o egluro'r gofynion

Y ffordd allan o'r sefyllfa hon oedd integreiddio'r injan jBPM i mewn i rai cynhyrchion sydd â'r prosesau busnes mwyaf cymhleth. Yn y tymor byr, cafodd yr ateb hwn beth llwyddiant: daeth yn bosibl gweithredu prosesau busnes cymhleth tra'n cynnal diagram gweddol addysgiadol a chyfoes yn y nodiant. BPMN2.

Integreiddio arddull BPM
Rhan fach o broses fusnes gymhleth

Yn y tymor hir, nid oedd yr ateb yn cyd-fynd â disgwyliadau: nid oedd dwysedd llafur uchel creu prosesau busnes trwy offer gweledol yn caniatáu cyflawni dangosyddion cynhyrchiant derbyniol, a daeth yr offeryn ei hun yn un o'r rhai nad oedd yn ei hoffi fwyaf ymhlith datblygwyr. Roedd cwynion hefyd am strwythur mewnol yr injan, a arweiniodd at ymddangosiad llawer o “glytiau” a “baglau”.

Y brif agwedd gadarnhaol ar ddefnyddio jBPM oedd gwireddu'r manteision a'r niwed o gael ei gyflwr parhaus ei hun ar gyfer achos proses fusnes. Gwelsom hefyd y posibilrwydd o ddefnyddio dull proses i weithredu protocolau integreiddio cymhleth rhwng gwahanol gymwysiadau gan ddefnyddio rhyngweithiadau anghydamserol trwy signalau a negeseuon. Mae presenoldeb cyflwr parhaus yn chwarae rhan hanfodol yn hyn.

Yn seiliedig ar yr uchod, gallwn ddod i'r casgliad: Mae'r dull proses yn arddull BPM yn ein galluogi i ddatrys ystod eang o dasgau ar gyfer awtomeiddio prosesau busnes cynyddol gymhleth, ffitio gweithgareddau integreiddio yn gytûn i'r prosesau hyn a chadw'r gallu i arddangos y broses a weithredwyd yn weledol mewn nodiant addas.

Anfanteision galwadau cydamserol fel patrwm integreiddio

Mae integreiddio cydamserol yn cyfeirio at yr alwad blocio symlaf. Mae un is-system yn gweithredu fel ochr y gweinydd ac yn datgelu'r API gyda'r dull a ddymunir. Mae is-system arall yn gweithredu fel ochr cleient ac, ar yr amser iawn, yn gwneud galwad gyda'r disgwyl o ganlyniad. Yn dibynnu ar bensaernïaeth y system, gellir cynnal ochr y cleient a'r gweinydd naill ai yn yr un cymhwysiad a phroses, neu mewn rhai gwahanol. Yn yr ail achos, mae angen i chi gymhwyso rhywfaint o weithrediad RPC a darparu marsialu'r paramedrau a chanlyniad yr alwad.

Integreiddio arddull BPM

Mae gan batrwm integreiddio o'r fath set eithaf mawr o anfanteision, ond fe'i defnyddir yn eang iawn yn ymarferol oherwydd ei symlrwydd. Mae cyflymder gweithredu yn swyno ac yn gwneud ichi ei gymhwyso dro ar ôl tro yn amodau terfynau amser “llosgi”, gan ysgrifennu'r ateb i ddyled dechnegol. Ond mae hefyd yn digwydd bod datblygwyr dibrofiad yn ei ddefnyddio'n anymwybodol, yn syml heb sylweddoli'r canlyniadau negyddol.

Yn ogystal â'r cynnydd mwyaf amlwg yng nghysylltiad is-systemau, mae problemau llai amlwg gyda thrafodion "lledaenu" ac "ymestyn". Yn wir, os yw rhesymeg y busnes yn gwneud unrhyw newidiadau, yna mae trafodion yn anhepgor, ac mae trafodion, yn eu tro, yn cloi rhai adnoddau cymwysiadau y mae'r newidiadau hyn yn effeithio arnynt. Hynny yw, nes bod un is-system yn aros am ymateb gan un arall, ni fydd yn gallu cwblhau'r trafodiad a rhyddhau cloeon. Mae hyn yn cynyddu'r risg o amrywiaeth o effeithiau yn sylweddol:

  • mae ymatebolrwydd y system yn cael ei golli, mae defnyddwyr yn aros am amser hir am atebion i geisiadau;
  • mae'r gweinydd yn gyffredinol yn rhoi'r gorau i ymateb i geisiadau defnyddwyr oherwydd pwll edau gorlifo: mae'r rhan fwyaf o'r edafedd yn “sefyll” ar glo'r adnodd a feddiannir gan y trafodiad;
  • mae cloeon llwyr yn dechrau ymddangos: mae'r tebygolrwydd y byddant yn digwydd yn dibynnu'n fawr ar hyd y trafodion, faint o resymeg busnes a chloeon sy'n gysylltiedig â'r trafodiad;
  • gwallau terfyn amser terfyn trafodiad yn ymddangos;
  • mae'r gweinydd yn “cwympo” ar OutOfMemory os yw'r dasg yn gofyn am brosesu a newid llawer iawn o ddata, ac mae presenoldeb integreiddiadau cydamserol yn ei gwneud hi'n anodd iawn rhannu'r prosesu yn drafodion “ysgafnach”.

O safbwynt pensaernïol, mae'r defnydd o alwadau blocio yn ystod integreiddio yn arwain at golli rheolaeth ansawdd is-systemau unigol: mae'n amhosibl sicrhau targedau ansawdd un is-system ar wahân i dargedau ansawdd is-system arall. Os caiff is-systemau eu datblygu gan dimau gwahanol, mae hon yn broblem fawr.

Mae pethau'n dod yn fwy diddorol fyth os yw'r is-systemau sy'n cael eu hintegreiddio mewn gwahanol gymwysiadau a bod angen gwneud newidiadau cydamserol ar y ddwy ochr. Sut i wneud y newidiadau hyn yn drafodion?

Os gwneir newidiadau mewn trafodion ar wahân, yna bydd angen trin eithriadau cadarn ac iawndal, ac mae hyn yn dileu'n llwyr brif fantais integreiddiadau cydamserol - symlrwydd.

Mae trafodion dosbarthedig hefyd yn dod i'r meddwl, ond nid ydym yn eu defnyddio yn ein hatebion: mae'n anodd sicrhau dibynadwyedd.

"Saga" fel ateb i'r broblem o drafodion

Gyda phoblogrwydd cynyddol microwasanaethau, mae galw cynyddol am Patrwm Saga.

Mae'r patrwm hwn yn berffaith yn datrys y problemau uchod o drafodion hir, ac mae hefyd yn ehangu'r posibiliadau o reoli cyflwr y system o ochr rhesymeg busnes: efallai na fydd iawndal ar ôl trafodiad aflwyddiannus yn treiglo'r system yn ôl i'w gyflwr gwreiddiol, ond yn darparu dewis arall. llwybr prosesu data. Mae hefyd yn caniatáu ichi beidio ag ailadrodd camau prosesu data a gwblhawyd yn llwyddiannus pan geisiwch ddod â'r broses i ddiweddglo “da”.

Yn ddiddorol, mewn systemau monolithig, mae'r patrwm hwn hefyd yn berthnasol o ran integreiddio is-systemau sydd wedi'u cyplysu'n llac ac mae effeithiau negyddol yn cael eu hachosi gan drafodion hir a'r cloeon adnoddau cyfatebol.

O ran ein prosesau busnes yn arddull BPM, mae'n troi allan i fod yn hawdd iawn gweithredu'r Sagas: gellir gosod camau unigol y Sagas fel gweithgareddau o fewn y broses fusnes, ac mae cyflwr parhaus y broses fusnes yn pennu, ymhlith pethau eraill, cyflwr mewnol y Sagas. Hynny yw, nid oes angen unrhyw fecanwaith cydgysylltu ychwanegol arnom. Y cyfan sydd ei angen arnoch yw brocer negeseuon gyda chefnogaeth ar gyfer gwarantau "o leiaf unwaith" fel cludiant.

Ond mae gan ateb o'r fath ei "bris" ei hun hefyd:

  • mae rhesymeg busnes yn mynd yn fwy cymhleth: mae angen i chi gyfrifo iawndal;
  • bydd angen rhoi'r gorau i gysondeb llawn, a all fod yn arbennig o sensitif ar gyfer systemau monolithig;
  • mae'r bensaernïaeth yn dod ychydig yn fwy cymhleth, mae angen ychwanegol am brocer negeseuon;
  • bydd angen offer monitro a gweinyddu ychwanegol (er yn gyffredinol mae hyn hyd yn oed yn dda: bydd ansawdd y gwasanaeth system yn cynyddu).

Ar gyfer systemau monolithig, nid yw'r cyfiawnhad dros ddefnyddio "Sags" mor amlwg. Ar gyfer microservices a SOAs eraill, lle, yn fwyaf tebygol, mae brocer eisoes, ac aberthwyd cysondeb llawn ar ddechrau'r prosiect, gall manteision defnyddio'r patrwm hwn fod yn sylweddol fwy na'r anfanteision, yn enwedig os oes API cyfleus yn y lefel rhesymeg busnes.

Amgáu rhesymeg busnes mewn microwasanaethau

Pan ddechreuon ni arbrofi gyda microwasanaethau, cododd cwestiwn rhesymol: ble i roi rhesymeg busnes y parth mewn perthynas â'r gwasanaeth sy'n darparu dyfalbarhad data parth?

Wrth edrych ar bensaernïaeth amrywiol BPMS, gall ymddangos yn rhesymol i wahanu rhesymeg busnes oddi wrth ddyfalbarhad: creu haen o wasanaethau meicro llwyfan a pharth sy'n ffurfio'r amgylchedd a'r cynhwysydd ar gyfer gweithredu rhesymeg busnes parth, a threfnu dyfalbarhad data parth ar wahân. haen o ficrowasanaethau syml iawn ac ysgafn. Mae prosesau busnes yn yr achos hwn yn trefnu gwasanaethau'r haen dyfalbarhad.

Integreiddio arddull BPM

Mae mantais fawr iawn i'r dull hwn: gallwch chi gynyddu ymarferoldeb y platfform cymaint ag y dymunwch, a dim ond yr haen gyfatebol o ficrowasanaethau platfform fydd yn “mynd yn dew” o hyn. Mae prosesau busnes o unrhyw barth yn cael y cyfle ar unwaith i ddefnyddio ymarferoldeb newydd y platfform cyn gynted ag y caiff ei ddiweddaru.

Datgelodd astudiaeth fanylach ddiffygion sylweddol yn y dull hwn:

  • mae gwasanaeth platfform sy'n gweithredu rhesymeg busnes llawer o barthau ar yr un pryd â risgiau mawr fel un pwynt methiant. Mae newidiadau aml i resymeg busnes yn cynyddu'r risg o fygiau sy'n arwain at fethiannau ar draws y system;
  • materion perfformiad: mae rhesymeg busnes yn gweithio gyda'i ddata trwy ryngwyneb cul ac araf:
    • bydd y data unwaith eto'n cael ei drefnu a'i bwmpio drwy'r pentwr rhwydwaith;
    • bydd y gwasanaeth parth yn aml yn dychwelyd mwy o ddata nag sydd ei angen ar y rhesymeg busnes ar gyfer prosesu, oherwydd galluoedd paramedroli ymholiad annigonol ar lefel API allanol y gwasanaeth;
    • gall sawl darn annibynnol o resymeg busnes ail-wneud cais am yr un data dro ar ôl tro i'w brosesu (gallwch liniaru'r broblem hon trwy ychwanegu ffa sesiwn sy'n storio data, ond mae hyn yn cymhlethu'r bensaernïaeth ymhellach ac yn creu problemau ffresni data ac annilysu cache);
  • materion trafodaethol:
    • prosesau busnes gyda chyflwr parhaus storio gan y gwasanaeth llwyfan yn anghyson â data parth, ac nid oes unrhyw ffyrdd hawdd i ddatrys y broblem hon;
    • symud clo data parth allan o'r trafodiad: os oes angen i'r rhesymeg busnes parth wneud newidiadau, ar ôl gwirio cywirdeb y data gwirioneddol yn gyntaf, mae angen eithrio'r posibilrwydd o newid cystadleuol yn y data wedi'i brosesu. Gall blocio data yn allanol helpu i ddatrys y broblem, ond mae datrysiad o'r fath yn cario risgiau ychwanegol ac yn lleihau dibynadwyedd cyffredinol y system;
  • cymhlethdodau ychwanegol wrth ddiweddaru: mewn rhai achosion, mae angen i chi ddiweddaru'r gwasanaeth dyfalbarhad a rhesymeg busnes yn gydamserol neu mewn dilyniant llym.

Yn y diwedd, roedd yn rhaid i mi fynd yn ôl at y pethau sylfaenol: crynhoi data parth a rhesymeg busnes parth yn un microwasanaeth. Mae'r dull hwn yn symleiddio'r canfyddiad bod y microwasanaeth yn rhan annatod o'r system ac nid yw'n achosi'r problemau uchod. Nid yw hyn hefyd yn rhad ac am ddim:

  • Mae angen safoni API ar gyfer rhyngweithio â rhesymeg busnes (yn benodol, i ddarparu gweithgareddau defnyddwyr fel rhan o brosesau busnes) a gwasanaethau llwyfan API; mae angen rhoi sylw mwy gofalus i newidiadau API, cydnawsedd ymlaen ac yn ôl;
  • mae'n ofynnol ychwanegu llyfrgelloedd amser rhedeg ychwanegol i sicrhau bod y rhesymeg fusnes yn gweithredu fel rhan o bob meicrowasanaeth o'r fath, ac mae hyn yn arwain at ofynion newydd ar gyfer llyfrgelloedd o'r fath: ysgafnder a lleiafswm o ddibyniaethau dros dro;
  • mae angen i ddatblygwyr rhesymeg busnes gadw golwg ar fersiynau llyfrgell: os nad yw microwasanaeth wedi'i gwblhau ers amser maith, yna mae'n debygol y bydd yn cynnwys fersiwn hen ffasiwn o'r llyfrgelloedd. Gall hyn fod yn rhwystr annisgwyl i ychwanegu nodwedd newydd a gall olygu bod angen symud hen resymeg busnes gwasanaeth o'r fath i fersiynau newydd o'r llyfrgelloedd pe bai newidiadau anghydnaws rhwng fersiynau.

Integreiddio arddull BPM

Mae haen o wasanaethau platfform hefyd yn bresennol mewn pensaernïaeth o'r fath, ond nid yw'r haen hon bellach yn ffurfio cynhwysydd ar gyfer gweithredu rhesymeg busnes parth, ond dim ond ei amgylchedd, gan ddarparu swyddogaethau "platfform" ategol. Mae angen haen o'r fath nid yn unig i gynnal ysgafnder microservices parth, ond hefyd i ganoli rheolaeth.

Er enghraifft, mae gweithgareddau defnyddwyr mewn prosesau busnes yn cynhyrchu tasgau. Fodd bynnag, wrth weithio gyda thasgau, rhaid i'r defnyddiwr weld tasgau o bob parth yn y rhestr gyffredinol, sy'n golygu bod yn rhaid cael gwasanaeth llwyfan cofrestru tasg priodol, wedi'i glirio o resymeg busnes parth. Mae cadw'r amgįu o resymeg busnes yn y cyd-destun hwn yn eithaf problemus, a dyma gyfaddawd arall ar y bensaernïaeth hon.

Integreiddio prosesau busnes trwy lygaid datblygwr cais

Fel y soniwyd eisoes uchod, rhaid tynnu datblygwr y cais o nodweddion technegol a pheirianneg gweithrediad rhyngweithiad sawl cais er mwyn gallu cyfrif ar gynhyrchiant datblygu da.

Gadewch i ni geisio datrys problem integreiddio eithaf anodd, a ddyfeisiwyd yn arbennig ar gyfer yr erthygl. Bydd hon yn dasg "gêm" yn cynnwys tri chymhwysiad, lle mae pob un ohonynt yn diffinio rhywfaint o enw parth: "app1", "app2", "app3".

Y tu mewn i bob cais, mae prosesau busnes yn cael eu lansio sy'n dechrau "chwarae pêl" trwy'r bws integreiddio. Bydd negeseuon o'r enw "Ball" yn gweithredu fel y bêl.

Rheolau'r gêm:

  • y chwaraewr cyntaf yw'r cychwynnwr. Mae'n gwahodd chwaraewyr eraill i'r gêm, yn dechrau'r gêm a gall ddod â hi i ben unrhyw bryd;
  • chwaraewyr eraill yn datgan eu cyfranogiad yn y gêm, "dod yn gyfarwydd" â'i gilydd a'r chwaraewr cyntaf;
  • ar ôl derbyn y bêl, mae'r chwaraewr yn dewis chwaraewr arall sy'n cymryd rhan ac yn trosglwyddo'r bêl iddo. Mae cyfanswm nifer y pasys yn cael ei gyfrif;
  • mae gan bob chwaraewr "ynni", sy'n lleihau gyda phob pasiad o'r bêl gan y chwaraewr hwnnw. Pan fydd yr egni'n dod i ben, caiff y chwaraewr ei ddileu o'r gêm, gan gyhoeddi ei ymddeoliad;
  • os gadewir y chwaraewr ar ei ben ei hun, mae'n datgan ei ymadawiad ar unwaith;
  • pan fydd yr holl chwaraewyr yn cael eu dileu, mae'r chwaraewr cyntaf yn datgan diwedd y gêm. Os gadawodd y gêm yn gynharach, yna mae'n aros i ddilyn y gêm er mwyn ei chwblhau.

I ddatrys y broblem hon, byddaf yn defnyddio ein DSL ar gyfer prosesau busnes, sy'n eich galluogi i ddisgrifio'r rhesymeg yn Kotlin yn gryno, gydag isafswm o boelerplate.

Yn y cais app1, bydd proses fusnes y chwaraewr cyntaf (ef hefyd yw cychwynnwr y gêm) yn gweithio:

Chwaraewr Cychwynnol dosbarth

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

Yn ogystal â gweithredu rhesymeg busnes, gall y cod uchod gynhyrchu model gwrthrych o broses fusnes y gellir ei ddelweddu fel diagram. Nid ydym wedi gweithredu'r delweddwr eto, felly bu'n rhaid i ni dreulio peth amser yn lluniadu (yma fe wnes i symleiddio'r nodiant BPMN ychydig ynglŷn â'r defnydd o gatiau i wella cysondeb y diagram â'r cod uchod):

Integreiddio arddull BPM

Bydd app2 yn cynnwys proses fusnes chwaraewr arall:

RandomPlayer dosbarth

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

Diagram:

Integreiddio arddull BPM

Yn y cais app3, byddwn yn gwneud y chwaraewr ag ymddygiad ychydig yn wahanol: yn lle dewis y chwaraewr nesaf ar hap, bydd yn gweithredu yn unol â'r algorithm robin crwn:

Dosbarth RowndRobinPlayer

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

Fel arall, nid yw ymddygiad y chwaraewr yn wahanol i'r un blaenorol, felly nid yw'r diagram yn newid.

Nawr mae angen prawf arnom i redeg y cyfan. Dim ond cod y prawf ei hun y byddaf yn ei roi, er mwyn peidio ag annibendod yr erthygl gyda phlât boeler (mewn gwirionedd, defnyddiais yr amgylchedd prawf a grëwyd yn gynharach i brofi integreiddio prosesau busnes eraill):

gêm brawf()

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

Rhedeg y prawf, edrychwch ar y log:

allbwn consol

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

Gellir dod i nifer o gasgliadau pwysig o hyn oll:

  • os yw'r offer angenrheidiol ar gael, gall datblygwyr cymwysiadau greu rhyngweithiadau integreiddio rhwng cymwysiadau heb dorri i ffwrdd o resymeg busnes;
  • gall cymhlethdod (cymhlethdod) tasg integreiddio sy'n gofyn am gymwyseddau peirianneg gael ei guddio y tu mewn i'r fframwaith os caiff ei osod i lawr i ddechrau ym mhensaernïaeth y fframwaith. Ni ellir cuddio anhawster y dasg (anhawster), felly bydd yr ateb i dasg anodd yn y cod yn edrych yn unol â hynny;
  • wrth ddatblygu rhesymeg integreiddio, mae angen cymryd i ystyriaeth yn y pen draw cysondeb a diffyg llinoledd y newid cyflwr yr holl gyfranogwyr integreiddio. Mae hyn yn ein gorfodi i gymhlethu'r rhesymeg er mwyn ei gwneud yn ansensitif i'r drefn y mae digwyddiadau allanol yn digwydd. Yn ein hesiampl, mae'r chwaraewr yn cael ei orfodi i gymryd rhan yn y gêm ar ôl iddo gyhoeddi ei allanfa o'r gêm: bydd chwaraewyr eraill yn parhau i drosglwyddo'r bêl iddo nes bod y wybodaeth am ei allanfa yn cyrraedd ac yn cael ei phrosesu gan yr holl gyfranogwyr. Nid yw'r rhesymeg hon yn dilyn o reolau'r gêm ac mae'n ateb cyfaddawd o fewn fframwaith y bensaernïaeth a ddewiswyd.

Nesaf, gadewch i ni siarad am y cynnil amrywiol ein datrysiad, cyfaddawdu a phwyntiau eraill.

Pob neges mewn un ciw

Mae pob cymhwysiad integredig yn gweithio gydag un bws integreiddio, a gyflwynir fel brocer allanol, un BPMQueue ar gyfer negeseuon ac un pwnc BPTopic ar gyfer signalau (digwyddiadau). Mae trosglwyddo pob neges trwy un ciw ynddo'i hun yn gyfaddawd. Ar lefel rhesymeg busnes, gallwch nawr gyflwyno cymaint o fathau newydd o negeseuon ag y dymunwch heb wneud newidiadau i strwythur y system. Mae hyn yn symleiddio sylweddol, ond mae iddo risgiau penodol, nad oedd, yng nghyd-destun ein tasgau nodweddiadol, yn ymddangos mor arwyddocaol i ni.

Integreiddio arddull BPM

Fodd bynnag, mae un cynildeb yma: mae pob cymhwysiad yn hidlo negeseuon "ei" o'r ciw wrth y fynedfa, yn ôl enw ei barth. Hefyd, gellir nodi'r parth yn y signalau, os oes angen i chi gyfyngu “cwmpas” y signal i un cymhwysiad sengl. Dylai hyn gynyddu lled band y bws, ond mae'n rhaid i'r rhesymeg busnes weithredu nawr gydag enwau parth: yn orfodol ar gyfer mynd i'r afael â negeseuon, yn ddymunol ar gyfer signalau.

Sicrhau dibynadwyedd y bws integreiddio

Mae dibynadwyedd yn cynnwys sawl peth:

  • Mae'r brocer negeseuon a ddewiswyd yn rhan hanfodol o'r bensaernïaeth ac yn un pwynt methiant: rhaid iddo allu goddef diffygion yn ddigonol. Dim ond gyda chefnogaeth dda a chymuned fawr y dylech ddefnyddio gweithrediadau prawf amser;
  • mae angen sicrhau argaeledd uchel y brocer negeseuon, y mae'n rhaid ei wahanu'n gorfforol oddi wrth y cymwysiadau integredig (mae argaeledd uchel cymwysiadau gyda rhesymeg busnes cymhwysol yn llawer anoddach a drud i'w darparu);
  • mae'n ofynnol i'r brocer ddarparu gwarantau dosbarthu "o leiaf unwaith". Mae hwn yn ofyniad gorfodol ar gyfer gweithrediad dibynadwy'r bws integreiddio. Nid oes angen gwarantau lefel "unwaith yn union": fel arfer nid yw prosesau busnes yn sensitif i negeseuon neu ddigwyddiadau sy'n cyrraedd dro ar ôl tro, ac mewn tasgau arbennig lle mae hyn yn bwysig, mae'n haws ychwanegu gwiriadau ychwanegol at resymeg busnes na'u defnyddio'n gyson. yn hytrach gwarantau "drud" ";
  • rhaid i anfon negeseuon a signalau fod yn rhan o drafodiad cyffredin gyda newid yng nghyflwr prosesau busnes a data parth. Y dewis a ffafrir fyddai defnyddio'r patrwm Blwch Allanol Trafodol, ond bydd angen tabl ychwanegol yn y gronfa ddata a chyfnewid. Mewn cymwysiadau JEE, gellir symleiddio hyn trwy ddefnyddio rheolwr JTA lleol, ond rhaid i'r cysylltiad â'r brocer a ddewiswyd allu gweithio yn y modd XA;
  • rhaid i drinwyr negeseuon a digwyddiadau sy'n dod i mewn hefyd weithio gyda'r trafodiad o newid cyflwr y broses fusnes: os yw trafodiad o'r fath yn cael ei rolio'n ôl, yna rhaid canslo derbyn y neges hefyd;
  • dylai negeseuon na ellid eu danfon oherwydd gwallau gael eu storio mewn storfa ar wahân Mae D.L.Q. (Ciw Llythyr Marw). I wneud hyn, rydym wedi creu meicrowasanaeth platfform ar wahân sy'n storio negeseuon o'r fath yn ei storfa, yn eu mynegeio yn ôl priodoleddau (ar gyfer grwpio a chwilio cyflym), ac yn datgelu'r API i'w wylio, ei ailgyfeirio i'r cyfeiriad cyrchfan, a dileu negeseuon. Gall gweinyddwyr systemau weithio gyda'r gwasanaeth hwn trwy eu rhyngwyneb gwe;
  • yn y gosodiadau brocer, mae angen i chi addasu nifer yr ailgeisiadau dosbarthu ac oedi rhwng danfoniadau er mwyn lleihau'r tebygolrwydd y bydd negeseuon yn mynd i mewn i'r DLQ (mae bron yn amhosibl cyfrifo'r paramedrau gorau posibl, ond gallwch chi weithredu'n empirig a'u haddasu yn ystod gweithrediad);
  • dylid monitro'r storfa DLQ yn barhaus, a dylai'r system fonitro hysbysu gweinyddwyr y system fel y gallant ymateb cyn gynted â phosibl pan fydd negeseuon heb eu danfon yn digwydd. Bydd hyn yn lleihau “parth difrod” methiant neu wall rhesymeg busnes;
  • rhaid i'r bws integreiddio fod yn ansensitif i absenoldeb dros dro ceisiadau: rhaid i danysgrifiadau pwnc fod yn wydn, a rhaid i enw parth y cais fod yn unigryw fel na fydd rhywun arall yn ceisio prosesu ei neges o'r ciw yn ystod absenoldeb y cais.

Sicrhau diogelwch llinyn o resymeg busnes

Gall yr un enghraifft o broses fusnes dderbyn sawl neges a digwyddiad ar unwaith, a bydd y prosesu yn dechrau ochr yn ochr. Ar yr un pryd, ar gyfer datblygwr cais, dylai popeth fod yn syml ac yn edau-ddiogel.

Mae rhesymeg busnes y broses yn prosesu pob digwyddiad allanol sy'n effeithio ar y broses fusnes hon yn unigol. Gall y digwyddiadau hyn fod yn:

  • lansio enghraifft o broses fusnes;
  • gweithred defnyddiwr sy'n ymwneud â gweithgaredd o fewn proses fusnes;
  • derbyn neges neu signal y mae enghraifft o broses fusnes wedi'i danysgrifio iddo;
  • diwedd yr amserydd a osodwyd gan yr enghraifft o broses fusnes;
  • rheoli gweithredu trwy API (e.e. erthylu proses).

Gall pob digwyddiad o'r fath newid cyflwr achos proses fusnes: gall rhai gweithgareddau ddod i ben ac eraill ddechrau, gall gwerthoedd eiddo parhaus newid. Gall cau unrhyw weithgaredd arwain at gychwyn un neu fwy o'r gweithgareddau canlynol. Gall y rheini, yn eu tro, roi'r gorau i aros am ddigwyddiadau eraill, neu, os nad oes angen unrhyw ddata ychwanegol arnynt, gallant gwblhau yn yr un trafodiad. Cyn cau'r trafodiad, mae cyflwr newydd y broses fusnes yn cael ei storio yn y gronfa ddata, lle bydd yn aros am y digwyddiad allanol nesaf.

Mae data prosesau busnes parhaus sy'n cael ei storio mewn cronfa ddata berthynol yn bwynt cydamseru prosesu cyfleus iawn wrth ddefnyddio SELECT FOR DIWEDDARIAD. Pe bai un trafodiad yn llwyddo i gael cyflwr y broses fusnes o'r gronfa ddata i'w newid, yna ni fydd unrhyw drafodiad arall ar y cyd yn gallu cael yr un cyflwr ar gyfer newid arall, ac ar ôl cwblhau'r trafodiad cyntaf, yr ail yw yn sicr o dderbyn y cyflwr sydd eisoes wedi newid.

Gan ddefnyddio cloeon pesimistaidd ar ochr DBMS, rydym yn cyflawni'r holl ofynion angenrheidiol ACID, a hefyd yn cadw'r gallu i raddfa'r cais gyda rhesymeg busnes trwy gynyddu nifer yr achosion rhedeg.

Fodd bynnag, mae cloeon pesimistaidd yn ein bygwth â chloeon digyfyngiad, sy'n golygu y dylai DEWIS I'W DDIWEDDARAF barhau i gael ei gyfyngu i gyfnod rhesymol o amser rhag ofn y bydd cyfyngiadau ar rai achosion aruthrol mewn rhesymeg busnes.

Problem arall yw cydamseru dechrau'r broses fusnes. Er nad oes enghraifft o broses fusnes, nid oes unrhyw gyflwr yn y gronfa ddata ychwaith, felly ni fydd y dull a ddisgrifir yn gweithio. Os ydych chi am sicrhau unigrywiaeth achos proses fusnes mewn cwmpas penodol, yna mae angen rhyw fath o wrthrych cydamseru arnoch chi sy'n gysylltiedig â'r dosbarth proses a'r cwmpas cyfatebol. I ddatrys y broblem hon, rydym yn defnyddio mecanwaith cloi gwahanol sy'n ein galluogi i gymryd clo ar adnodd mympwyol a bennir gan allwedd mewn fformat URI trwy wasanaeth allanol.

Yn ein henghreifftiau, mae proses fusnes BeginPlayer yn cynnwys datganiad

uniqueConstraint = UniqueConstraints.singleton

Felly, mae'r log yn cynnwys negeseuon am gymryd a rhyddhau clo'r allwedd gyfatebol. Nid oes unrhyw negeseuon o'r fath ar gyfer prosesau busnes eraill: ni osodir cyfyngiad unigryw.

Problemau prosesau busnes gyda chyflwr parhaus

Weithiau mae cael cyflwr parhaus nid yn unig yn helpu, ond hefyd yn rhwystro datblygiad mewn gwirionedd.
Mae problemau'n dechrau pan fydd angen i chi wneud newidiadau i'r rhesymeg busnes a/neu fodel proses fusnes. Ni cheir bod unrhyw newid o'r fath yn gydnaws â hen gyflwr y prosesau busnes. Os oes llawer o achosion "byw" yn y gronfa ddata, yna gall gwneud newidiadau anghydnaws achosi llawer o drafferth, y daethom ar ei draws yn aml wrth ddefnyddio jBPM.

Yn dibynnu ar ddyfnder y newid, gallwch weithredu mewn dwy ffordd:

  1. creu math o broses fusnes newydd er mwyn peidio â gwneud newidiadau anghydnaws i'r hen un, a'i ddefnyddio yn lle'r hen un wrth ddechrau achosion newydd. Bydd hen enghreifftiau yn parhau i weithio "yr hen ffordd";
  2. mudo cyflwr parhaus prosesau busnes wrth ddiweddaru rhesymeg busnes.

Mae'r ffordd gyntaf yn symlach, ond mae ganddi ei chyfyngiadau a'i hanfanteision, er enghraifft:

  • dyblygu rhesymeg busnes mewn llawer o fodelau prosesau busnes, cynnydd yn nifer y rhesymeg busnes;
  • yn aml mae angen newid ar unwaith i resymeg busnes newydd (bron bob amser o ran tasgau integreiddio);
  • nid yw'r datblygwr yn gwybod ar ba bwynt y mae'n bosibl dileu modelau darfodedig.

Yn ymarferol, rydym yn defnyddio’r ddau ddull, ond rydym wedi gwneud nifer o benderfyniadau i symleiddio ein bywydau:

  • yn y gronfa ddata, mae cyflwr parhaus y broses fusnes yn cael ei storio mewn ffurf hawdd ei darllen a'i phrosesu'n hawdd: mewn llinyn fformat JSON. Mae hyn yn caniatáu ichi gyflawni mudo y tu mewn i'r cais a'r tu allan. Mewn achosion eithafol, gallwch hefyd ei addasu gyda dolenni (yn arbennig o ddefnyddiol wrth ddatblygu yn ystod dadfygio);
  • nid yw'r rhesymeg busnes integreiddio yn defnyddio enwau prosesau busnes, felly ar unrhyw adeg mae'n bosibl disodli gweithrediad un o'r prosesau sy'n cymryd rhan gydag un newydd, gydag enw newydd (er enghraifft, "InitialPlayerV2"). Mae'r rhwymiad yn digwydd trwy enwau negeseuon a signalau;
  • mae gan y model proses rif fersiwn, y byddwn yn ei gynyddu os byddwn yn gwneud newidiadau anghydnaws i'r model hwn, a bod y rhif hwn yn cael ei storio ynghyd â chyflwr yr enghraifft broses;
  • mae cyflwr parhaus y broses yn cael ei ddarllen o'r sylfaen yn gyntaf i fodel gwrthrych cyfleus y gall y weithdrefn fudo weithio gydag ef os yw rhif fersiwn y model wedi newid;
  • gosodir y weithdrefn fudo wrth ymyl rhesymeg y busnes ac fe'i gelwir yn "ddiog" ar gyfer pob achos o'r broses fusnes ar adeg ei adfer o'r gronfa ddata;
  • os oes angen i chi fudo cyflwr yr holl achosion proses yn gyflym ac yn gydamserol, defnyddir atebion mudo cronfa ddata mwy clasurol, ond mae'n rhaid i chi weithio gyda JSON yno.

A oes angen fframwaith arall arnaf ar gyfer prosesau busnes?

Roedd yr atebion a ddisgrifir yn yr erthygl yn caniatáu inni symleiddio ein bywydau yn sylweddol, ehangu'r ystod o faterion a ddatryswyd ar lefel datblygu cymwysiadau, a gwneud y syniad o wahanu rhesymeg busnes yn ficrowasanaethau yn fwy deniadol. Ar gyfer hyn, mae llawer o waith wedi'i wneud, mae fframwaith "ysgafn" iawn ar gyfer prosesau busnes wedi'i greu, yn ogystal ag elfennau gwasanaeth ar gyfer datrys y problemau a nodwyd yng nghyd-destun ystod eang o dasgau cymhwysol. Mae gennym awydd i rannu'r canlyniadau hyn, i ddod â datblygiad cydrannau cyffredin i fynediad agored o dan drwydded am ddim. Bydd hyn yn gofyn am rywfaint o ymdrech ac amser. Gallai deall y galw am atebion o'r fath fod yn gymhelliant ychwanegol i ni. Yn yr erthygl arfaethedig, ychydig iawn o sylw a roddir i alluoedd y fframwaith ei hun, ond mae rhai ohonynt yn weladwy o'r enghreifftiau a gyflwynir. Os byddwn serch hynny yn cyhoeddi ein fframwaith, bydd erthygl ar wahân yn cael ei neilltuo iddo. Yn y cyfamser, byddwn yn ddiolchgar os byddwch yn gadael ychydig o adborth drwy ateb y cwestiwn:

Dim ond defnyddwyr cofrestredig all gymryd rhan yn yr arolwg. Mewngofnodios gwelwch yn dda.

A oes angen fframwaith arall arnaf ar gyfer prosesau busnes?

  • 18,8%Ydw, rydw i wedi bod yn chwilio am rywbeth fel hyn ers amser maith.

  • 12,5%mae'n ddiddorol dysgu mwy am eich gweithrediad, gallai fod yn ddefnyddiol2

  • 6,2%rydym yn defnyddio un o'r fframweithiau presennol, ond rydym yn meddwl am ei ddisodli1

  • 18,8%rydym yn defnyddio un o'r fframweithiau presennol, mae popeth yn gweddu3

  • 18,8%ymdopi heb fframwaith3

  • 25,0%ysgrifennu eich hun 4

Pleidleisiodd 16 o ddefnyddwyr. Ataliodd 7 o ddefnyddwyr.

Ffynhonnell: hab.com

Ychwanegu sylw