BPM style integrationem

BPM style integrationem

,, RџSЂRoRІRμS Habr!

Societas nostra speciale est in evolutione solutionum ERP-classis programmatum, in qua leone participes occupantur systemata transactionali cum ingenti copia negotii logicae et laboris a la EDMS. Nostrae productorum versiones modernae in JavaEE technologiae fundatae sunt, sed etiam actuose experimenta cum microservices etiam experimur. Una ex maxime areis problematicis talium solutionum est integratio variarum subsystematum ad regiones vicinas pertinentium. Officia integralia semper nobis praebuerunt ingentem capitis rationem, cuiuscumque styli architecturae, technologiae acervos et compages utimur, sed nuper progressus est ad huiusmodi problemata solvenda.

In articulo ad mentem tuam perductus, de experientia et inquisitione architecturae NPO Krista in spatio designato loquar. Exemplum etiam simplicis solutionis ad problema integrationis inspiciemus ex parte applicationis elit et quid post hanc simplicitatem lateat cognoscamus.

Disclaimer

Solutiones architecturae et technicae in articulo de quibus a me oblatae sunt in usu personali in contextu officiorum propriorum. Hae solutiones non dicunt universales esse nec optimales esse aliis condicionibus usuum.

Quid BPM ad rem?

Ad hanc quaestionem solvendam, necesse est aliquantulum in particularia problematum solutionum applicatarum inspicere. Praecipua pars negotii logicae in systemate nostro typico transactionali data in datorum intrat per interfaces usorum, manually et automatice hanc datam inhibens, eam per aliquot fluxum laboris praeteriens, eam ad alium systema / datorum analyticorum / archivi, relationum generans. Ita munus clavem systematis clientium automation est processus negotiorum internorum.

Pro commodo, "documenti" in communicatione utimur sicut aliqua abstractio notitiarum statutorum, a communi clavibus unitorum, cui certae laboris fluxus "adiungi" potest.
Sed quid de logica integratione? Ceterum, munus integrationis ab architectura systematis generatur, quod "scidit" in partes NON rogatu emptoris, sed impulsu diversorum factorum;

  • under the influence of Conway's law;
  • ex causa reuse subsystematum pro aliis productis antea elaboratis;
  • sicut ab architecto constitutum est, in non-muneris requisitis.

Magna tentatio est separare logicam integrationem a negotio logicae praecipui laboris incepti, ne logica negotia cum artificialibus integratione polluat et applicatione elit, ne in proprias tabulae architecturae systematis involvatur. Hic aditus plures utilitates habet, sed usus inefficacem ostendit;

  • problemata integratio solvenda plerumque labitur ad optiones simplicissimas in forma vocat synchroni ob limitata extensionis puncta in exsequenda principali workflui (magis in defectibus integrationis synchronae infra);
  • artificialia integratio adhuc principale negotium logicum penetrant, cum feedback ex alio subsystem exigitur;
  • elit applicationis integrationem abicit et eam facile immutando workflui infringere potest;
  • systema desinit esse unum totum ex parte usoris, "summe" inter subsystematum notabilis fiunt, operationes usoris redundans apparent quae translationem notitiarum ab uno subsystem in alium inchoant.

Alia accessio est considerare interactiones integrales sicut pars integralis nuclei negotii logicae et laboris fluxus. Ad arte requisita applicationis tincidunt a skyrocketing, novas interationes integrationes creando faciliter et naturaliter faciendae sunt, cum minimum optiones solutionis eligendae. Hoc difficilius est quam spectat: instrumentum validum esse debet ut usorem necessariam optionum varietatem ad suum usum praebeat et simul se in pede emittere non sinat. Multae interrogationes sunt quas ingeniarius in contextu operis integrationis respondere debet, sed quas applicatio elit non debet cogitare de in opere cotidiano: transactionis limites, constantia, atomicity, securitatis, scalae, oneris et opum distributio, eiectio, institutio; Propagationis et mutandi contextus etc. Necesse est ut applicationes tincidunt praebeant ad propositas propositiones satis simplices, in quibus respondetur omnibus huiusmodi quaestionibus iam absconditis. Haec exemplaria satis tuta debent esse: logica negotia saepissime mutat, quae periculum introducendi errorum auget, sumptus errorum sub aequo manere debet.

Sed tamen quid BPM ad rem pertinet? Multae optiones ad exsequendam workflow ...
Re quidem vera alia exsecutio processuum negotiorum est valde popularis in solutionibus nostris - per declarativum occasum status transitus schematis et tracto connectens cum negotio logicae ad transitiones. Eodem tempore status, qui praesentem statum "documenti" determinat in processu negotii, attributum est ipsius "documenti".

BPM style integrationem
Hoc modo processus spectat sicut ad initium documenti

Talis exsecutio favoris debetur simplicitati relativae et celeritati processus negotium conficiendi lineares. Sed, cum systemata programmata magis implicata fiunt, pars automated negotii processum crescit et magis implicatur. Opus est compositione, reuse partium processuum, tum processus furcis, ut uterque ramus in parallelis efficiatur. Talibus conditionibus instrumentum incommodum fit, et status transitus schematis notitias suas amittit (interationes integrationes in schemate omnino non reflectuntur).

BPM style integrationem
Hoc est quod processus similis videtur post varias iterationes necessarias illustrandas

Via huius rei erat integratio machinae jBPM in nonnullis productis cum negotiorum processibus complexissimis. In verbo brevi, haec solutio aliquos successus habuit: facta est possibilis ad effectum deducendi processuum negotiorum implicatorum, servato satis informativo et recenti schemate in notatione. BPMN2.

BPM style integrationem
Parva pars negotii processus implicati

In longum tempus, solutio ad exspectationem non vixit: summus labor intensio negotii faciendi processuum per instrumenta visualia non permittit ut acceptissimas fructibus indicibus assequendis, et ipsum instrumentum fiebat inter tincidunt maxime odiosum. Erant etiam querelae de structura machinae internae, quae ad aspectum plurium inaequalitatum et fuscarum adduxit.

Praecipua ratio positiva utendi jBPM erat effectio beneficiorum et nocumenti se habens statum suum pertinaciter ad instantiam negotiorum processum. Vidimus etiam facultatem utendi accessus ad perficiendum complexum integrationem protocolla inter varias applicationes utendi asynchronis commercio per signa et nuntios. Praesentia civitatis persistentis magnae in hoc munere agit.

Ex superioribus concludere possumus: Processus accessus in stilo BPM nobis permittit ut amplis muneribus solvendis pro processibus negotiis implicatis automando, harmonice aptando actiones integrationis in his processibus, et facultatem retineamus ut processus effectum deducendi in congrua notatione visibiliter ostendat.

Incommoda synchrone vocat ad integrationem exemplaris

Integratio synchrona intelligitur interclusio simplicissima vocatio. Una subsystem lateri servo fungitur et API methodo desiderata patefacit. Alia subsystem parte clientis agit et, in tempore, cum exspectatione effectus invitat. Secundum architecturae systematis, clientis et servientis latera possunt vel in eadem applicatione et processu, vel in diversis. In secundo casu, vos postulo RPC exsecutionem aliquam adhibere et parametri parametri rationem praebere et eventum vocationis adhibere.

BPM style integrationem

Huiusmodi integratio exemplaris incommodis maiusculas habet, sed in usu longe late patet propter eius simplicitatem. Celeritas exsecutionis captat et iterum iterumque applicatur in condicionibus "ustionis" fatalium, solutionem scribentis in debitum technicum. Sed etiam accidit ut tincidunt imperiti utantur ea inscii, simpliciter non animadvertentes consectaria negativa.

Praeter notissima incrementa in nexu subsystematis, minus obviae sunt difficultates cum transactionibus "divulgare" et "extendere". Immo, si logica negotia aliquas mutationes facit, negotiationes necessariae sunt, et transactiones vicissim claudunt quasdam applicationes facultates his mutationibus affectas. Hoc est, donec unus subsystem responsum ab alio exspectet, transactionem absolvere et comas emittere non poterit. Hoc periculum varietas effectuum auget significanter;

  • ratio alacritatis perit, utentes diu exspectant responsa petitionibus;
  • server plerumque cessat respondere petitionibus usoris ob stamina inundantis piscinae: pleraque staminum "statis" in lock subsidii a negotio occupatae;
  • deadlocks incipiunt apparere: probabilitas eorum occurrentiae valde pendet a duratione transactionum, quantitate negotii logicae et comis in negotio negotiorum;
  • transaction timeout acto erroris apparent;
  • server "cadit" in OutOfMemory si negotium exigat processus et mutans magnas copiae notitiarum, et praesentia integrationum synchronarum perdifficile est scindendi processum in transactiones "leviores".

Ex parte architecturae, usus interclusionis vocat in integratione ad detrimentum qualitatis subsystematum singularum: impossibile est curare qualitates scutorum unius subsystem in seiunctis a qualitate scutorum alterius subsystem. Si subsystema diversis iugis explicantur, magnum problema est.

Quae plus iucunda sunt si subsystema integrata sunt in variis applicationibus et mutationes synchronae utrinque faciendae sunt. Quomodo hae mutationes transactionales?

Si mutationes fiunt in singulis negotiis, tunc robusta exceptio tractatio et emendatio praestanda erit, et haec utilitas summam integrationum synchronae - simplicitatis omnino tollit.

Transactiones distributae in mentem veniunt, sed in solutionibus nostris non utimur: difficile est efficere constantiam.

"Saga" tamquam solutionem problematis transactions

Crescente favore microofficiorum, crescit postulatio Saga Exemplum.

Praefecti perfecte dissolvit praedictas quaestiones longarum transactionum, et etiam facultates disponendi statum systematis ex parte negotii logicae dilatat: mercedis post infelicis transactionis rationem ad pristinum statum non revolvere potest, sed alterum praebere. MGE iter. Etiam permittit tibi ne feliciter confecta processus processus gressus repetere velis cum processum ad finem "bonum" deducere conaris.

Interestingly, in systematibus monolithicis, hoc exemplar etiam pertinet cum ad integrationem subsystematum laxe copulatorum pervenit et effectus negativi ex longis transactionibus et correspondentibus subsidiis crines causantur.

Quod ad negotium nostrum processuum in stilo BPM attinet, facillime evenit Sagas efficiendi: singulae gradus Sagas constitui possunt ut actiones in processu negotiorum, et statu negotiorum pervicax constituitur; alia, internus Sagas. Hoc est, coordinationis mechanismi additamento non indigemus. Omnes opus est nuntius sectorem cum auxilio "saltem semel" cautiones ut onerariae.

Sed haec solutio etiam suum "pretium" habet;

  • negotium logica magis implicat: emendare debes;
  • plenam constantiam deserere oportebit, quae maxime sensibilis in systematibus monolithicis esse potest;
  • architectura paulo intricatior fit, accedit opus sectoris;
  • addita vigilantia et administratio instrumenta requirentur (quamvis generatim hoc etiam bonum sit: qualitas muneris augebit ratio).

Pro monolithicis systematibus, iustificatio utendi "Sags" non ita evidens est. Pro microservices et aliis SOAs, ubi, verisimile, iam sectorem esse, et plenam constantiam in initio propositi immolatum, beneficia exemplaris adhibita signanter incommoda praeponderant, praesertim si commodum est API in negotium logice ordinare.

Encapsulation logicae negotii in microservices

Cum experimentum in microservices experiri coepimus, quaestio rationabilis orta est: ubi ponere logicam negotiationem domain in relatione ad servitium quod pertinaciam praebet domain data?

Cum ad architecturam variarum BPMS spectantes, rationabilibus negotium logicum a perseverantia separandum videri potest: accumsan suggesti et dominici micromeritorum independentium creare, quae ambitum et continentem formant ad exsequendam logicam negotiationem negotiandi, ac pervicacia ut separatum data ditione disponere. layer of very simple and lightweight microservices. Negotium processus in hoc casu orchestrate officia assiduitatis accumsan.

BPM style integrationem

Accessus hic plus habet maximos: augere potes functionem suggesti quantum libet, et tantum congruens iacuit e suggestus microservices ex hoc "pinguedo". Negotiatio processus ex quavis ditione statim occasionem nactus est utendi nova functionalitate suggesti quam primum renovata est.

Accuratius studium significans defectus huius ac- tionis revelavit:

  • ministerium tribunal quod negotium logice multarum provinciarum exercet simul magna pericula in uno puncto deficiendi portat. Crebrae mutationes logicae negotiorum augent periculum cimicum qui systematis defectibus amplis feruntur;
  • quaestiones perficiendi: logica negotiatio cum suis notitia per interfaciem angustum et tardum;
    • data iterum per ACERVUS retis instruantur et exantlarentur;
    • servitium dominicum saepe plus notitiae reddere quam logica negotia processus requirit, ob insufficiens facultates parameterizationis quaesitionis in gradu servitii externi API;
    • plures logicae negotiationes independentes identidem postulare possunt eandem datam ad expediendum (hoc problema addendo fabam cella datam diminuere potes, sed hoc ulterius inpedimenta architecturae et problemata novitatis et cellae invalidationis data);
  • quaestiones transactional:
    • processus negotiorum cum statu assiduo, repositorum a tribunali muneris, repugnant notitiae ditionis, et modi non sunt faciles ad hanc solvendam quaestionem;
    • clavem dominii datae ex transactione movendo: si logica negotiatio domain mutare debet, postquam rectitudo actualis notitiae inprimitur, necessarium est excludere possibilitatem competitive mutationis in data processit. Externa notitiarum interclusio adiuvare potest problema solvendum, sed talis solutio pericula additional portat et universalem fidem systematis minuit;
  • adiectis complicationibus cum adaequationis: in quibusdam casibus debes renovare assiduitatem servitio et negotio logicae synchrone vel stricte seriei.

In fine, redire debebam ad basics: encapsulate domain data et negotia logica domain in unam microserviam. Hic accessus perceptionem microservii ut partem integralem in systemate simpliciorem reddit neque praedictas difficultates oriuntur. Etiam id libero neque;

  • API standardisation requiritur ad commercium cum logica negotiatione (praesertim ut usorum actiones praebeat processuum negotiorum) et API officia suggesta; diligentius observandum est ut API mutationes, ante et retro convenientiae requiratur;
  • oportet insuper bibliothecas runtimes addere, ut logicae negotium in parte uniuscuiusque huiusmodi microserviciis fungatur, quod sequitur novas necessitates pro talibus bibliothecis: levitatem et minimum dependentiarum transitivarum;
  • negotia logica tincidunt opus est ut versiones bibliothecae custodiant: si microservice diu non completa est, tunc maxime verisimile est versionem librariorum iam receptam contineri. Hoc inopinatum impedimentum esse potest ad novam notam addendo et requirat logicam rem veterem talis servitii ad novas bibliothecarum versiones migrandum, si inter versiones mutationes non desint.

BPM style integrationem

Etiam in tali architectura iacuit officia suggestiva, sed haec tabula non amplius continens ad exsequendam logicam negotiationem domain, sed solum eius ambitum, munera "platform" auxiliaria praebens. Talis strato opus est non solum ad levitatem servitiorum domain conservandam, sed etiam ad administrationem centralem faciendam.

Exempli gratia, actiones in negotiorum processuum opera usorum generant. Nihilominus, cum opus est muneribus, usor debet videre officia ab omnibus dominiis in indice generali, quod significat debere esse congruum munus adnotatione tribunalis muneris, purgato negotiorum regio logicae. Servans encapsulationis logicae negotii in hoc loco admodum inconveniens est, et haec est alia transactio huius architecturae.

Integrationem negotii processuum per oculos applicationis elit

Ut iam dictum est, elit applicationis abstrahi debet a technicis et technicis notis ad exsecutionem commercii plurium applicationum, ut bonae evolutionis fructibus numerare valeamus.

Studeamus problema integrationem difficiliorem solvere, specialiter ad articulum inventam. Hoc erit munus "ludus" tria applicationes implicare, in quibus unaquaeque earum definit nomen quoddam domain: "app1", "app2", "app3".

Intra unamquamque applicationem, processus negotii causantur qui "pilam ludere" per integrationem bus incipiunt. Epistulae nomine "Ball" pro pila aget.

De ludum praecepta:

  • Primus tibicen est initiator. Alios histriones ad ludum invitat, ludum incipit et aliquando finire potest;
  • alii lusores suam participationem in ludo "noscendo" declarant inter se et primum lusorem;
  • post pilam acceptam, lusor alium lusorem participandum eligit et pilam ad eum transit. Numerus transitus numeratur;
  • uterque lusor "energiam" habet, quae cum quolibet transitu pilae ab illo lusore decrescit. Cum vis excurrit, lusor a ludo removetur, otium suum nuntians;
  • si lusor solus relictus est, statim discessum suum declarat;
  • omnibus histriones eliminatis, primus lusor ludi finem declarat. Si e ludo prius discessit, restat ut lusum sequendum ad perficiendum.

Ad hanc solvendam quaestionem, DSL nostro processuum negotiorum utar, qui logicam in Kotlin compacte cum minimum boilerplate describere tibi sinit.

In applicatione, processus negotii primi lusoris (ipse est etiam initium ludi) operabitur;

genus InitialPlayer

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

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

class PlayersList : ArrayList<PlayerInfo>()

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

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

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

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

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

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

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

Praeter logicam negotiationem exsequendam, codice supradictus exemplar obiectum negotii processui producere potest, qui ut schema subjici potest. Non tamen visualisorem ad effectum adduximus, ut tempus aliquod trahere debeamus (hic notationem BPMN leviter simpliciorem de usu portarum ad crassitudinem schematis cum codice superiore emendare);

BPM style integrationem

app2 aliam rem processus ludio ludius includit:

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

Tabulae:

BPM style integrationem

In app3 applicatione lusorem cum paulo diversis moribus faciemus: loco passim proximum lusorem eligens, secundum algorithmum rotundum-robin aget;

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

Aliter ludi mores a priori non differt, sic schema non mutat.

Nunc experimento opus est ut omnia curramus. Solum codicem ipsius testi dabo, ut articulum cum boilerplate non clutem (enim, antea probatum ambitus creatum usus sum ad integrationem aliorum processuum negotiorum probandam);

testGame ()

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

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

Curre test, ecce truncum:

consolamini output

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

Ex his omnibus multae conclusiones momenti sumi possunt:

  • si instrumenta necessaria suppetunt, applicationes tincidunt integrationem inter applicationes inter applicationes integrationem creare possunt quin a logica negotiatione dimittant;
  • multiplicitas (complexitas) integrationis munus quod requirit facultates machinales intra ambitum occultari potest si initio in compage architectura statuitur. Difficultas negotii (difficultatis) occultari non potest, ideoque solutio difficultatis in codice prospiciet;
  • cum logicam integrationem enucleat, oportet tandem rationem habere constantiae ac defectus linearizabilitatis status mutationis omnium participantium integrationis. Hoc nos cogit logicam implicare ut insensibilem reddat ordinem in quo res externae fiunt. In exemplo nostro lusor lusori interesse cogitur postquam e ludo exitum suum nuntiat: alii lusores pilam ad eum transibunt usque dum informationes de exitu eius attingit et ab omnibus participantibus processit. Haec logica ex regulis ludi non sequitur et est compromissum solutionis intra ambitum architecturae electae.

Deinde de variis solutionis, mediis, et aliis punctis, de subtilitatibus loquamur.

Omnes nuntii in queue

Omnes applicationes integrae operantur cum uno bus integrationibus, quae sectorem externum exhibentur, unum BPMQueue pro nuntiis et unum BPMTopic thema pro significationibus (eventorum). Transiens omnes nuntios per unum queue in se ipsum compromissum est. In gradu logicae negotii, tot novas epistularum genera nunc introducere potes quantum vis sine mutationibus structurae systematis. Significans haec simplicitas est, sed quaedam pericula fert, quae, in contextu nostro munerum propriorum, nobis non ita significantes videbantur.

BPM style integrationem

Nihilominus una subtilitas hic est: unaquaeque applicatio nuntiis "eius" a queue in introitu, nomine dominii sui. Item, dominium definiri potest in significationibus, si necesse est "scopum" signi ad unam applicationem circumscribere. Haec band latitudo augere debet, sed logica negotiatio nunc operari debet cum nominibus dominicis: nuncius pro nuntiis alloquendis, pro significationibus expetendis.

Prospicere fidem bus integrationis

Fiducia constat ex pluribus rebus;

  • Electus nuntius sector est critica pars architecturae et unum punctum defectionis: debet satis esse culpae tolerantior. Modo probata opera bono auxilio et magna communitate utere debes;
  • necesse est curare altam promptitudinem nuntii sectoris, ad quod physice separandum est ab applicationibus integris (alta dispositio applicationum cum logica negotiis applicatis multo difficilius et sumptuosius providendum est);
  • sector tenetur "saltem semel" traditionis cautiones. Haec mandati actio est pro certa operatione integrationis bus. Nihil opus est "prorsus semel" gradu cautionibus: processus negotiandi plerumque non insensibiles sunt ad recipiendas nuntios vel eventus, et in specialibus officiis ubi hoc interest, facilius est adiectas impedimenta logicae negotiorum addere quam assidue uti. "pretium" "spondet;
  • nuntiis et significationibus mittendis implicari debent in communi transactione cum mutatione status negotiorum processuum et notitiarum domain. Praelata optio esset ut exemplar Transactional Outboxsed in datorum ac curriculo tabulam additam requiret. In applicationibus JEE, hoc simplicior fieri potest utendo procuratori locali JTA, sed nexus ad sectorem delecti modo operari potest. XA;
  • tractatores nuntii et eventus advenientis operari etiam debent cum transactione mutandi status negotii processui: si talis transactionis revolvitur, acceptio nuntii etiam cassanda est;
  • nuntia, quae ex erroribus tradi non poterant, in thesauro separato reponebantur D.L.Q. (Epistola mortua Queue). Ad hoc faciendum, microservice suggestum separatum creavimus, qui tales nuntios in repositione reponit, indices attributorum (ad vivos adjunctio et inquisitione), et API ad videndum, ad destinatum locum aperiendum et nuntios deletis exponit. Systema administratores hoc ministerio per interretiales eorum operari possunt;
  • in uncinis sectoris, numerum retrarum ac moras inter deliberandas accommodare debes ut verisimilitudo nuntiorum in DLQ ingressuri redigatur (seu parametros optimales computare fere impossibile est, sed empirice agere potes et eas in aptare. operatio);
  • the DLQ promptuarium continue viverra debet, et ratio vigilantia administratores ratis certiorem facere debet ut quam celerrime respondeant, cum undeliberi nuntii occurrant. Hoc "zonam damni" reducet in errore logicae defectus vel negotii;
  • bus integratio insensibilis esse debet ad absentiam applicationum temporalem: subscriptiones thema esse debent durabiles, et nomen regio applicationis unicum esse debet ut alius non conetur suum nuntium a queue in absentia applicationis procedere.

Prosequens filum logicae negotii salus

Eadem instantia negotii processum plures nuntios et eventus simul recipere potest, quorum processus in parallelis incipiet. Eodem tempore, ad applicationem elit, omnia simplicia et tuta esse debent.

De processu negotii logicae processus cuiusque eventus externi, qui hoc negotiorum processum singulariter afficit. Haec certe possunt esse;

  • negotium processum deductis exempli gratia;
  • a user actio ad actionem in negotio processus;
  • accepto nuntio vel signo cui negotium processus instantia subscripsit;
  • expleto tempore per processum negotii, exempli gratia;
  • actio control per API (exampla abort).

Uterque talis eventus statum negotii processum mutare potest, exempli gratia: aliae actiones finire possunt, aliae incipere, valores proprietatum pertinarum mutare possunt. Operatio quaelibet occlusa inveniatur in activatione unius vel plurium sequentium actionum. Illi autem prohibere possunt alias eventus exspectare, vel, si nulla additamenta requirunt, in eodem negotio perficere possunt. Antequam rem gestam claudant, novus processus rerum status in datorum reponitur, ubi proximum externum eventum exspectabit.

Processus negotii perseverans notitia reposita in database relatione relationis est punctum opportunum processus synchronisationi cum utens SELECT PRO UPDATE. Si quis negotium procuraverit ut status negotii processum a datorum mutaverit, nulla alia res in parallelis eundem statum alterius mutationis obtinere poterit, et post primam transactionem confectam, altera est. recep- turum jam mutatam rempublicam.

Utentes in pessimam partem in DBMS comis, omnia necessaria requisita implemus ACIDUMac etiam facultatem obtinent applicationes ad rem logicam ascendendi, crescente numero instantiarum currentium.

Sed comae pessimae nobis deadlocks minantur, quod significat ut UPDATE SELECTO adhuc aliquo rationabili tempore circumscribi debet in casu deadlocks in aliquibus egregiis casibus in negotio logicae.

Alia quaestio synchronisation est processus negotii initium. Cum exempli gratia processus negotii non est, nulla in re publica aut in datorum, sic descripta ratio operabitur. Si vis efficere singularitatem negotii processus instantiae in particulari ambitu, tunc opus est aliqua re synchronisationi coniuncta cum processu classium et scopo congruenti. Ad hanc quaestionem solvendam, alia mechanismo densis utimur, quae nos sinit crinem sumere in subsidio arbitrario specifico per clavem in forma URI per servitium externum.

In nostris exemplis, processus negotiationis initialPlayer declarationem continet

uniqueConstraint = UniqueConstraints.singleton

Ideo index epistulas continet de capiendo et solvendo clavem clavem respondentis. Nullae tales nuntii pro aliis processibus negotii sunt: ​​unicumConstraint non est positum.

Negotium processus problems cum pertinaci statu

Pertinax interdum habens statum non solum adiuvat, sed etiam progressionem vere impedit.
Problemata incipiunt cum debes mutationes facere ad rem logicam et / vel ad exemplar processus negotii. Nec ullus talis mutatio status negotiorum processuum compatitur apud veteres. Si plures instantiae "vivunt" in datorum datorum, tum incompatibilia mutationes multam molestiam afferre possunt, quod saepe cum jBPM utendo offendit.

Secundum altitudinem mutationis, duobus modis agere potes.

  1. novum negotium processum genus creandum est, ut non repugnet mutationi veteri, eoque loco veteri utatur cum instantiis novis incipiendis. Veteres instantiae pergunt ad laborem "via vetus";
  2. negotiorum processuum statum pertinaciter migrandum cum adaequationis negotiorum logicalium.

Simplicior est via prima, sed habet limitationes et incommoda, ut:

  • de duplicatione negotii logicae, in multis exemplaribus negotii processus, aucto tomo negotii logicae;
  • saepe instans transitus ad novum negotium logicum requiritur (semper fere verbis integrationis munerum);
  • elit nesciat quo in loco exempla obsoleta delere possit.

Utroque usu in usu utimur, sed complura decisiones ad simpliciorem vitam nostram fecerunt;

  • in datorum, constans status negotii processum reponitur in forma facili facilique processu: in chorda JSON format. Hoc tibi permittit ut migrationes tam intra applicationes quam extra peragas. In casibus extremas, etiam manubriis illud vellicare potes (praesertim in evolutione in debugging utilis);
  • negotium logica integratio non utitur nominibus negotiorum processuum, ita ut aliquando substituere possit exsequendam processuum participationis cum novo nomine, nomine novo (exempli gratia "InitialPlayerV2"). Obligatio per nuntios et significationum nomina;
  • exemplar processus habet numerum versionis, quam augemus, si huic exemplarii mutationes incompatibilia facimus, et hic numerus reponitur una cum statu processus instantiae;
  • processus status constans ex basi primum in obiectum conveniente legitur exemplar quod migratio processus operari potest, si numerus exemplaris versionis mutatus est;
  • processus migrationis iuxta negotium logicum ponitur et vocatur "piger" pro unoquoque instantia processus negotiorum tempore datorum a datorum restitutione;
  • si statum omnium processuum instantiarum cito et synchrone migrare debes, solutiones migrationum datorum magis classicarum adhibentur, sed opus est tibi cum JSON ibi.

Mihi opus est alia compage pro processibus negotii?

Solutiones in articulo descriptae nobis significanter simpliciores animas nostras permiserunt, ampliare ampliationem quaestionum solvendae in gradu applicationis evolutionis, et notionem logicam separandi in microservices magis amabilius. Propter hoc, multum laboris peractum est, compago admodum "levis" negotii processuum creata est, necnon partes muneris ad solvendas quaestiones identificas in contextu amplis applicatorum officiorum. Hos eventus participare cupimus, communium partium progressionem in apertam accessum sub libera licentia adducere. Hic quaerat aliquam laboris et tempore. Intellectus postulatio huiusmodi solutionum nobis adici potuit incitamentum. In articulo propositi, parum attenditur ad capacitatem ipsius compagis, sed quaedam earum ex exemplis allatis conspicua sunt. Si nihilominus nostram compagem evulgamus, articulus separatus in eo erit. Interim gratus erimus si aliquantulum opiniones interrogationi respondendo relinquas;

Tantum usores descripserunt in aliquet participare possunt. InscribeTe gratissimum esse.

Mihi opus est alia compage pro processibus negotii?

  • 18,8%Ita diu aliquid simile quaesivi.

  • 12,5%interest scire plura de tua exsecutione, ut sit utilis2

  • 6,2%utimur una compage exsistentium, sed cogitamus de reponendo

  • 18,8%utimur una compage exsistentium, omnia suit3 .

  • 18,8%parietum sine framework3

  • 25,0%scribere own4

16 utentes censuerunt. 7 Utentes abstinuerunt.

Source: www.habr.com

Add a comment