BPM స్టైల్ ఇంటిగ్రేషన్

BPM స్టైల్ ఇంటిగ్రేషన్

, హలో హబ్ర్!

మా కంపెనీ ERP-తరగతి సాఫ్ట్‌వేర్ సొల్యూషన్‌ల అభివృద్ధిలో ప్రత్యేకత కలిగి ఉంది, దీనిలో సింహభాగం వ్యాపార లాజిక్ మరియు వర్క్‌ఫ్లో a la EDMS యొక్క భారీ మొత్తంలో లావాదేవీ వ్యవస్థలచే ఆక్రమించబడింది. మా ఉత్పత్తుల యొక్క ఆధునిక సంస్కరణలు JavaEE సాంకేతికతలపై ఆధారపడి ఉన్నాయి, కానీ మేము మైక్రోసర్వీస్‌లతో కూడా చురుకుగా ప్రయోగాలు చేస్తున్నాము. అటువంటి పరిష్కారాల యొక్క అత్యంత సమస్యాత్మక ప్రాంతాలలో ఒకటి ప్రక్కనే ఉన్న డొమైన్‌లకు సంబంధించిన వివిధ ఉపవ్యవస్థల ఏకీకరణ. మేము ఉపయోగించే నిర్మాణ శైలులు, టెక్నాలజీ స్టాక్‌లు మరియు ఫ్రేమ్‌వర్క్‌లతో సంబంధం లేకుండా ఇంటిగ్రేషన్ పనులు ఎల్లప్పుడూ మాకు పెద్ద తలనొప్పిని ఇస్తున్నాయి, అయితే ఇటీవల అటువంటి సమస్యలను పరిష్కరించడంలో పురోగతి ఉంది.

మీ దృష్టికి తీసుకువచ్చిన వ్యాసంలో, నియమించబడిన ప్రాంతంలో NPO క్రిస్టా యొక్క అనుభవం మరియు నిర్మాణ పరిశోధన గురించి నేను మాట్లాడతాను. అప్లికేషన్ డెవలపర్ దృక్కోణం నుండి ఇంటిగ్రేషన్ సమస్యకు సరళమైన పరిష్కారం యొక్క ఉదాహరణను కూడా మేము పరిశీలిస్తాము మరియు ఈ సరళత వెనుక దాగి ఉన్న వాటిని కనుగొంటాము.

నిరాకరణ

వ్యాసంలో వివరించిన నిర్మాణ మరియు సాంకేతిక పరిష్కారాలు నిర్దిష్ట పనుల సందర్భంలో వ్యక్తిగత అనుభవం ఆధారంగా నాచే అందించబడ్డాయి. ఈ పరిష్కారాలు సార్వత్రికమైనవిగా క్లెయిమ్ చేయవు మరియు ఇతర ఉపయోగ పరిస్థితులలో సరైనవి కాకపోవచ్చు.

BPMకి దానితో సంబంధం ఏమిటి?

ఈ ప్రశ్నకు సమాధానమివ్వడానికి, మా పరిష్కారాల యొక్క అనువర్తిత సమస్యల యొక్క ప్రత్యేకతలను మనం కొంచెం లోతుగా పరిశోధించాలి. వినియోగదారు ఇంటర్‌ఫేస్‌ల ద్వారా డేటాబేస్‌లోకి డేటాను నమోదు చేయడం, మాన్యువల్‌గా మరియు స్వయంచాలకంగా ఈ డేటాను తనిఖీ చేయడం, కొంత వర్క్‌ఫ్లో ద్వారా దానిని పంపడం, మరొక సిస్టమ్ / విశ్లేషణాత్మక డేటాబేస్ / ఆర్కైవ్‌లో ప్రచురించడం, నివేదికలను రూపొందించడం మా సాధారణ లావాదేవీల వ్యవస్థలోని వ్యాపార తర్కం యొక్క ప్రధాన భాగం. అందువల్ల, కస్టమర్ల కోసం సిస్టమ్ యొక్క ముఖ్య విధి వారి అంతర్గత వ్యాపార ప్రక్రియల ఆటోమేషన్.

సౌలభ్యం కోసం, మేము కమ్యూనికేషన్‌లో "డాక్యుమెంట్" అనే పదాన్ని డేటా సెట్ యొక్క కొంత సంగ్రహంగా ఉపయోగిస్తాము, ఒక సాధారణ కీ ద్వారా ఏకం చేయబడుతుంది, దీనికి నిర్దిష్ట వర్క్‌ఫ్లో "అటాచ్ చేయవచ్చు".
కానీ ఇంటిగ్రేషన్ లాజిక్ గురించి ఏమిటి? అన్నింటికంటే, ఇంటిగ్రేషన్ యొక్క పని సిస్టమ్ యొక్క ఆర్కిటెక్చర్ ద్వారా ఉత్పత్తి చేయబడుతుంది, ఇది కస్టమర్ యొక్క అభ్యర్థన మేరకు కాదు, పూర్తిగా భిన్నమైన కారకాల ప్రభావంతో భాగాలుగా "రంపబడుతుంది":

  • కాన్వే చట్టం ప్రభావంతో;
  • ఇతర ఉత్పత్తుల కోసం గతంలో అభివృద్ధి చేసిన ఉపవ్యవస్థల పునర్వినియోగం ఫలితంగా;
  • నాన్-ఫంక్షనల్ అవసరాల ఆధారంగా వాస్తుశిల్పి నిర్ణయించినట్లు.

ఇంటిగ్రేషన్ కళాఖండాలతో వ్యాపార తర్కాన్ని కలుషితం చేయకుండా మరియు సిస్టమ్ యొక్క నిర్మాణ ప్రకృతి దృశ్యం యొక్క ప్రత్యేకతలను లోతుగా పరిశోధించకుండా అప్లికేషన్ డెవలపర్‌ను రక్షించకుండా ఉండటానికి, ప్రధాన వర్క్‌ఫ్లో యొక్క వ్యాపార తర్కం నుండి ఇంటిగ్రేషన్ లాజిక్‌ను వేరు చేయడానికి గొప్ప టెంప్టేషన్ ఉంది. ఈ విధానం అనేక ప్రయోజనాలను కలిగి ఉంది, కానీ అభ్యాసం దాని అసమర్థతను చూపుతుంది:

  • ఏకీకరణ సమస్యలను పరిష్కరించడం సాధారణంగా ప్రధాన వర్క్‌ఫ్లో అమలులో పరిమిత పొడిగింపు పాయింట్ల కారణంగా సింక్రోనస్ కాల్‌ల రూపంలో సరళమైన ఎంపికలకు జారిపోతుంది (క్రింద ఉన్న సింక్రోనస్ ఇంటిగ్రేషన్ యొక్క లోపాలపై మరిన్ని);
  • మరొక ఉపవ్యవస్థ నుండి అభిప్రాయం అవసరమైనప్పుడు ఏకీకరణ కళాఖండాలు ఇప్పటికీ ప్రధాన వ్యాపార తర్కంలోకి చొచ్చుకుపోతాయి;
  • అప్లికేషన్ డెవలపర్ ఏకీకరణను విస్మరిస్తాడు మరియు వర్క్‌ఫ్లోను మార్చడం ద్వారా దానిని సులభంగా విచ్ఛిన్నం చేయవచ్చు;
  • సిస్టమ్ వినియోగదారు యొక్క దృక్కోణం నుండి ఒకే మొత్తంగా నిలిచిపోతుంది, ఉపవ్యవస్థల మధ్య "అతుకులు" గుర్తించదగినవిగా మారతాయి, అనవసరమైన వినియోగదారు కార్యకలాపాలు కనిపిస్తాయి, ఇవి ఒక సబ్‌సిస్టమ్ నుండి మరొకదానికి డేటా బదిలీని ప్రారంభిస్తాయి.

కోర్ బిజినెస్ లాజిక్ మరియు వర్క్‌ఫ్లో యొక్క అంతర్భాగంగా ఇంటిగ్రేషన్ ఇంటరాక్షన్‌లను పరిగణించడం మరొక విధానం. అప్లికేషన్ డెవలపర్‌ల నైపుణ్య అవసరాలు ఆకాశాన్నంటకుండా ఉండటానికి, కొత్త ఇంటిగ్రేషన్ ఇంటరాక్షన్‌లను సృష్టించడం సులభంగా మరియు సహజంగా, పరిష్కారాన్ని ఎంచుకోవడానికి కనీస ఎంపికలతో చేయాలి. ఇది కనిపించే దానికంటే చాలా కష్టం: సాధనం దాని ఉపయోగం కోసం అవసరమైన వివిధ రకాల ఎంపికలను వినియోగదారుకు అందించడానికి తగినంత శక్తివంతంగా ఉండాలి మరియు అదే సమయంలో తమను తాము పాదాలకు కాల్చడానికి అనుమతించదు. ఇంటిగ్రేషన్ టాస్క్‌ల సందర్భంలో ఇంజనీర్ తప్పనిసరిగా సమాధానమివ్వాల్సిన అనేక ప్రశ్నలు ఉన్నాయి, కానీ అప్లికేషన్ డెవలపర్ వారి రోజువారీ పని గురించి ఆలోచించకూడదు: లావాదేవీ సరిహద్దులు, స్థిరత్వం, పరమాణువు, భద్రత, స్కేలింగ్, లోడ్ మరియు వనరుల పంపిణీ, రూటింగ్, మార్షలింగ్, ప్రచారం మరియు స్విచ్చింగ్ సందర్భాలు మొదలైనవి. అప్లికేషన్ డెవలపర్‌లకు చాలా సరళమైన నిర్ణయ టెంప్లేట్‌లను అందించడం అవసరం, ఇందులో అటువంటి ప్రశ్నలన్నింటికీ సమాధానాలు ఇప్పటికే దాచబడ్డాయి. ఈ నమూనాలు తగినంత సురక్షితంగా ఉండాలి: వ్యాపార తర్కం చాలా తరచుగా మారుతుంది, ఇది లోపాలను పరిచయం చేసే ప్రమాదాన్ని పెంచుతుంది, లోపాల ధర చాలా తక్కువ స్థాయిలో ఉండాలి.

కానీ ఇప్పటికీ, BPM దానితో ఏమి చేయాలి? వర్క్‌ఫ్లో అమలు చేయడానికి అనేక ఎంపికలు ఉన్నాయి ...
నిజానికి, వ్యాపార ప్రక్రియల యొక్క మరొక అమలు మా పరిష్కారాలలో బాగా ప్రాచుర్యం పొందింది - రాష్ట్ర పరివర్తన రేఖాచిత్రం యొక్క డిక్లరేటివ్ సెట్టింగ్ మరియు పరివర్తనలకు వ్యాపార లాజిక్‌తో హ్యాండ్లర్‌లను కనెక్ట్ చేయడం ద్వారా. అదే సమయంలో, వ్యాపార ప్రక్రియలో "పత్రం" యొక్క ప్రస్తుత స్థితిని నిర్ణయించే స్థితి "పత్రం" యొక్క లక్షణం.

BPM స్టైల్ ఇంటిగ్రేషన్
ప్రాజెక్ట్ ప్రారంభంలో ఈ ప్రక్రియ ఎలా ఉంటుంది

అటువంటి అమలు యొక్క ప్రజాదరణ సరళ వ్యాపార ప్రక్రియలను సృష్టించే సాపేక్ష సరళత మరియు వేగం కారణంగా ఉంది. అయినప్పటికీ, సాఫ్ట్‌వేర్ వ్యవస్థలు మరింత సంక్లిష్టంగా మారడంతో, వ్యాపార ప్రక్రియ యొక్క స్వయంచాలక భాగం పెరుగుతుంది మరియు మరింత క్లిష్టంగా మారుతుంది. కుళ్ళిపోవడం, ప్రక్రియల భాగాల పునర్వినియోగం, అలాగే ఫోర్కింగ్ ప్రక్రియల అవసరం ఉంది, తద్వారా ప్రతి శాఖ సమాంతరంగా అమలు చేయబడుతుంది. అటువంటి పరిస్థితులలో, సాధనం అసౌకర్యంగా మారుతుంది మరియు రాష్ట్ర పరివర్తన రేఖాచిత్రం దాని సమాచార కంటెంట్‌ను కోల్పోతుంది (ఏకీకరణ పరస్పర చర్యలు రేఖాచిత్రంలో ప్రతిబింబించవు).

BPM స్టైల్ ఇంటిగ్రేషన్
అవసరాలను స్పష్టం చేయడానికి అనేక పునరావృతాల తర్వాత ప్రక్రియ ఇలా కనిపిస్తుంది

ఈ పరిస్థితి నుండి బయటపడటానికి మార్గం ఇంజిన్ యొక్క ఏకీకరణ jBPM అత్యంత క్లిష్టమైన వ్యాపార ప్రక్రియలతో కొన్ని ఉత్పత్తుల్లోకి. స్వల్పకాలంలో, ఈ పరిష్కారం కొంత విజయాన్ని సాధించింది: సంజ్ఞామానంలో చాలా సమాచార మరియు తాజా రేఖాచిత్రాన్ని కొనసాగిస్తూ సంక్లిష్ట వ్యాపార ప్రక్రియలను అమలు చేయడం సాధ్యమైంది. BPMN2.

BPM స్టైల్ ఇంటిగ్రేషన్
సంక్లిష్ట వ్యాపార ప్రక్రియలో చిన్న భాగం

దీర్ఘకాలంలో, పరిష్కారం అంచనాలకు అనుగుణంగా లేదు: దృశ్య సాధనాల ద్వారా వ్యాపార ప్రక్రియలను సృష్టించే అధిక శ్రమ తీవ్రత ఆమోదయోగ్యమైన ఉత్పాదకత సూచికలను సాధించడానికి అనుమతించలేదు మరియు డెవలపర్‌లలో ఈ సాధనం చాలా ఇష్టపడని వాటిలో ఒకటిగా మారింది. ఇంజిన్ యొక్క అంతర్గత నిర్మాణం గురించి ఫిర్యాదులు కూడా ఉన్నాయి, ఇది అనేక "పాచెస్" మరియు "క్రచెస్" రూపానికి దారితీసింది.

jBPMని ఉపయోగించడంలో ప్రధాన సానుకూల అంశం ఏమిటంటే, వ్యాపార ప్రక్రియ ఉదాహరణ కోసం దాని స్వంత స్థిరమైన స్థితిని కలిగి ఉండటం వల్ల కలిగే ప్రయోజనాలు మరియు హానిలను గ్రహించడం. సిగ్నల్‌లు మరియు సందేశాల ద్వారా అసమకాలిక పరస్పర చర్యలను ఉపయోగించి వివిధ అప్లికేషన్‌ల మధ్య సంక్లిష్టమైన ఇంటిగ్రేషన్ ప్రోటోకాల్‌లను అమలు చేయడానికి ప్రాసెస్ విధానాన్ని ఉపయోగించే అవకాశాన్ని కూడా మేము చూశాము. స్థిరమైన రాష్ట్ర ఉనికి ఇందులో కీలక పాత్ర పోషిస్తుంది.

పైన పేర్కొన్నదాని ఆధారంగా, మేము ముగించవచ్చు: BPM స్టైల్‌లోని ప్రాసెస్ విధానం మరింత సంక్లిష్టమైన వ్యాపార ప్రక్రియలను ఆటోమేట్ చేయడానికి విస్తృత శ్రేణి పనులను పరిష్కరించడానికి అనుమతిస్తుంది, ఈ ప్రక్రియలలో ఏకీకరణ కార్యకలాపాలను శ్రావ్యంగా అమర్చండి మరియు అమలు చేయబడిన ప్రక్రియను తగిన సంజ్ఞామానంలో దృశ్యమానంగా ప్రదర్శించే సామర్థ్యాన్ని కలిగి ఉంటుంది.

ఏకీకరణ నమూనాగా సమకాలిక కాల్స్ యొక్క ప్రతికూలతలు

సింక్రోనస్ ఇంటిగ్రేషన్ అనేది సరళమైన బ్లాక్ చేసే కాల్‌ని సూచిస్తుంది. ఒక సబ్‌సిస్టమ్ సర్వర్ సైడ్‌గా పనిచేస్తుంది మరియు కావలసిన పద్ధతితో APIని బహిర్గతం చేస్తుంది. మరొక సబ్‌సిస్టమ్ క్లయింట్ సైడ్‌గా పనిచేస్తుంది మరియు సరైన సమయంలో, ఫలితం ఆశించి కాల్ చేస్తుంది. సిస్టమ్ ఆర్కిటెక్చర్ ఆధారంగా, క్లయింట్ మరియు సర్వర్ వైపులా ఒకే అప్లికేషన్ మరియు ప్రాసెస్‌లో లేదా వేర్వేరు వాటిల్లో హోస్ట్ చేయవచ్చు. రెండవ సందర్భంలో, మీరు RPC యొక్క కొంత అమలును వర్తింపజేయాలి మరియు పారామితుల మార్షలింగ్ మరియు కాల్ ఫలితాన్ని అందించాలి.

BPM స్టైల్ ఇంటిగ్రేషన్

ఇటువంటి ఏకీకరణ నమూనా చాలా పెద్ద లోపాలను కలిగి ఉంది, కానీ దాని సరళత కారణంగా ఇది చాలా విస్తృతంగా ఆచరణలో ఉపయోగించబడుతుంది. అమలు వేగం ఆకర్షణీయంగా ఉంటుంది మరియు సాంకేతిక రుణంగా పరిష్కారాన్ని వ్రాసి, "బర్నింగ్" గడువులో ఉన్న పరిస్థితుల్లో మీరు దాన్ని మళ్లీ మళ్లీ వర్తింపజేస్తుంది. కానీ అనుభవం లేని డెవలపర్లు దీనిని తెలియకుండానే ఉపయోగించుకుంటారు, ప్రతికూల పరిణామాలను గ్రహించలేరు.

ఉపవ్యవస్థల కనెక్టివిటీలో అత్యంత స్పష్టమైన పెరుగుదలతో పాటు, "వ్యాప్తి" మరియు "సాగదీయడం" లావాదేవీలతో తక్కువ స్పష్టమైన సమస్యలు ఉన్నాయి. నిజానికి, వ్యాపార తర్కం ఏదైనా మార్పులు చేస్తే, లావాదేవీలు అనివార్యమైనవి మరియు లావాదేవీలు, ఈ మార్పుల ద్వారా ప్రభావితమైన నిర్దిష్ట అప్లికేషన్ వనరులను లాక్ చేస్తాయి. అంటే, ఒక సబ్‌సిస్టమ్ మరొకరి నుండి ప్రతిస్పందన కోసం వేచి ఉండే వరకు, అది లావాదేవీని పూర్తి చేయడం మరియు లాక్‌లను విడుదల చేయడం సాధ్యం కాదు. ఇది వివిధ ప్రభావాల ప్రమాదాన్ని గణనీయంగా పెంచుతుంది:

  • సిస్టమ్ ప్రతిస్పందన పోతుంది, వినియోగదారులు అభ్యర్థనలకు సమాధానాల కోసం చాలా కాలం వేచి ఉంటారు;
  • ఓవర్‌ఫ్లోయింగ్ థ్రెడ్ పూల్ కారణంగా సర్వర్ సాధారణంగా వినియోగదారు అభ్యర్థనలకు ప్రతిస్పందించడం ఆపివేస్తుంది: చాలా థ్రెడ్‌లు లావాదేవీ ద్వారా ఆక్రమించబడిన వనరు యొక్క లాక్‌పై "నిలబడి" ఉంటాయి;
  • డెడ్‌లాక్‌లు కనిపించడం ప్రారంభిస్తాయి: వాటి సంభవించే సంభావ్యత లావాదేవీల వ్యవధి, వ్యాపార తర్కం మరియు లావాదేవీలో పాల్గొన్న తాళాల పరిమాణంపై బలంగా ఆధారపడి ఉంటుంది;
  • లావాదేవీ గడువు ముగింపు లోపాలు కనిపిస్తాయి;
  • టాస్క్‌కు పెద్ద మొత్తంలో డేటాను ప్రాసెస్ చేయడం మరియు మార్చడం అవసరమైతే సర్వర్ OutOfMemoryపై "పడిపోతుంది" మరియు సమకాలీకరణ అనుసంధానాల ఉనికిని ప్రాసెసింగ్‌ను "తేలికైన" లావాదేవీలుగా విభజించడం చాలా కష్టతరం చేస్తుంది.

నిర్మాణ దృక్కోణం నుండి, ఇంటిగ్రేషన్ సమయంలో కాల్‌లను నిరోధించడం వ్యక్తిగత ఉపవ్యవస్థల నాణ్యత నియంత్రణను కోల్పోయేలా చేస్తుంది: మరొక ఉపవ్యవస్థ కోసం నాణ్యత సూచికల నుండి ఒంటరిగా ఒక ఉపవ్యవస్థకు నాణ్యమైన లక్ష్యాలను సాధించడం అసాధ్యం. ఉపవ్యవస్థలు వేర్వేరు బృందాలచే అభివృద్ధి చేయబడితే, ఇది పెద్ద సమస్య.

అనుసంధానించబడిన ఉపవ్యవస్థలు వేర్వేరు అప్లికేషన్‌లలో ఉంటే విషయాలు మరింత ఆసక్తికరంగా ఉంటాయి మరియు రెండు వైపులా సమకాలీకరణ మార్పులు చేయవలసి ఉంటుంది. ఈ మార్పులను లావాదేవీలను ఎలా చేయాలి?

ప్రత్యేక లావాదేవీలలో మార్పులు జరిగితే, బలమైన మినహాయింపు నిర్వహణ మరియు పరిహారం అందించవలసి ఉంటుంది మరియు ఇది సింక్రోనస్ ఇంటిగ్రేషన్‌ల యొక్క ప్రధాన ప్రయోజనాన్ని పూర్తిగా తొలగిస్తుంది - సరళత.

పంపిణీ చేయబడిన లావాదేవీలు కూడా గుర్తుకు వస్తాయి, కానీ మేము వాటిని మా పరిష్కారాలలో ఉపయోగించము: విశ్వసనీయతను నిర్ధారించడం కష్టం.

లావాదేవీల సమస్యకు పరిష్కారంగా "సాగా"

మైక్రోసర్వీస్‌కు పెరుగుతున్న ప్రజాదరణతో, పెరుగుతున్న డిమాండ్ ఉంది సాగా నమూనా.

ఈ నమూనా సుదీర్ఘ లావాదేవీల యొక్క పై సమస్యలను సంపూర్ణంగా పరిష్కరిస్తుంది మరియు వ్యాపార లాజిక్ వైపు నుండి సిస్టమ్ యొక్క స్థితిని నిర్వహించే అవకాశాలను కూడా విస్తరిస్తుంది: విఫలమైన లావాదేవీ తర్వాత పరిహారం సిస్టమ్‌ను దాని అసలు స్థితికి వెనక్కి తీసుకోకపోవచ్చు, కానీ ప్రత్యామ్నాయాన్ని అందిస్తుంది. డేటా ప్రాసెసింగ్ మార్గం. మీరు ప్రక్రియను “మంచి” ముగింపుకు తీసుకురావడానికి ప్రయత్నించినప్పుడు విజయవంతంగా పూర్తయిన డేటా ప్రాసెసింగ్ దశలను పునరావృతం చేయకుండా కూడా ఇది మిమ్మల్ని అనుమతిస్తుంది.

ఆసక్తికరంగా, ఏకశిలా వ్యవస్థలలో, వదులుగా కపుల్డ్ సబ్‌సిస్టమ్‌ల ఏకీకరణ విషయానికి వస్తే ఈ నమూనా కూడా సంబంధితంగా ఉంటుంది మరియు సుదీర్ఘ లావాదేవీలు మరియు సంబంధిత రిసోర్స్ లాక్‌ల వల్ల ప్రతికూల ప్రభావాలు ఉన్నాయి.

BPM శైలిలో మా వ్యాపార ప్రక్రియలకు సంబంధించి, Sagasని అమలు చేయడం చాలా సులభం అవుతుంది: Sagas యొక్క వ్యక్తిగత దశలను వ్యాపార ప్రక్రియలో కార్యకలాపాలుగా సెట్ చేయవచ్చు మరియు వ్యాపార ప్రక్రియ యొక్క స్థిరమైన స్థితి ఇతర విషయాలతోపాటు నిర్ణయిస్తుంది , సాగస్ యొక్క అంతర్గత స్థితి. అంటే, మాకు అదనపు సమన్వయ యంత్రాంగం అవసరం లేదు. మీకు కావలసిందల్లా రవాణాగా "కనీసం ఒక్కసారి" హామీల కోసం మద్దతుతో సందేశ బ్రోకర్.

కానీ అలాంటి పరిష్కారానికి దాని స్వంత "ధర" కూడా ఉంది:

  • వ్యాపార తర్కం మరింత క్లిష్టంగా మారుతుంది: మీరు పరిహారం కోసం పని చేయాలి;
  • పూర్తి స్థిరత్వాన్ని వదిలివేయడం అవసరం, ఇది ఏకశిలా వ్యవస్థలకు ప్రత్యేకంగా సున్నితంగా ఉంటుంది;
  • ఆర్కిటెక్చర్ కొంచెం క్లిష్టంగా మారుతుంది, మెసేజ్ బ్రోకర్ కోసం అదనపు అవసరం ఉంది;
  • అదనపు పర్యవేక్షణ మరియు నిర్వహణ సాధనాలు అవసరం (సాధారణంగా ఇది కూడా మంచిది: సిస్టమ్ సేవ యొక్క నాణ్యత పెరుగుతుంది).

ఏకశిలా వ్యవస్థల కోసం, "సాగ్స్" ఉపయోగించడం కోసం సమర్థన అంత స్పష్టంగా లేదు. మైక్రోసర్వీస్ మరియు ఇతర SOAల కోసం, చాలా మటుకు, ఇప్పటికే బ్రోకర్ ఉన్నారు మరియు ప్రాజెక్ట్ ప్రారంభంలో పూర్తి అనుగుణ్యత త్యాగం చేయబడింది, ఈ నమూనాను ఉపయోగించడం వల్ల కలిగే ప్రయోజనాలు ప్రతికూలతలను గణనీయంగా అధిగమిస్తాయి, ప్రత్యేకించి అనుకూలమైన API ఉంటే వ్యాపార లాజిక్ స్థాయి.

మైక్రోసర్వీసెస్‌లో వ్యాపార తర్కం యొక్క ఎన్‌క్యాప్సులేషన్

మేము మైక్రోసర్వీస్‌లతో ప్రయోగాలు చేయడం ప్రారంభించినప్పుడు, ఒక సహేతుకమైన ప్రశ్న తలెత్తింది: డొమైన్ డేటా నిలకడను అందించే సేవకు సంబంధించి డొమైన్ బిజినెస్ లాజిక్‌ను ఎక్కడ ఉంచాలి?

వివిధ BPMS యొక్క నిర్మాణాన్ని చూసినప్పుడు, వ్యాపార తర్కాన్ని నిలకడ నుండి వేరు చేయడం సహేతుకంగా అనిపించవచ్చు: డొమైన్ వ్యాపార తర్కాన్ని అమలు చేయడానికి పర్యావరణం మరియు కంటైనర్‌ను రూపొందించే ప్లాట్‌ఫారమ్ మరియు డొమైన్-స్వతంత్ర మైక్రోసర్వీస్‌ల పొరను సృష్టించండి మరియు డొమైన్ డేటా నిలకడను ప్రత్యేకంగా ఏర్పాటు చేయండి. చాలా సులభమైన మరియు తేలికైన మైక్రోసర్వీస్‌ల పొర. ఈ సందర్భంలో వ్యాపార ప్రక్రియలు పెర్సిస్టెన్స్ లేయర్ యొక్క సేవలను ఆర్కెస్ట్రేట్ చేస్తాయి.

BPM స్టైల్ ఇంటిగ్రేషన్

ఈ విధానానికి చాలా పెద్ద ప్లస్ ఉంది: మీరు ప్లాట్‌ఫారమ్ యొక్క కార్యాచరణను మీకు నచ్చిన విధంగా పెంచవచ్చు మరియు ప్లాట్‌ఫారమ్ మైక్రోసర్వీస్‌ల యొక్క సంబంధిత పొర మాత్రమే దీని నుండి “కొవ్వు పొందుతుంది”. ఏదైనా డొమైన్ నుండి బిజినెస్ ప్రాసెస్‌లు అప్‌డేట్ అయిన వెంటనే ప్లాట్‌ఫారమ్ యొక్క కొత్త ఫంక్షనాలిటీని ఉపయోగించుకునే అవకాశాన్ని పొందుతాయి.

మరింత వివరణాత్మక అధ్యయనం ఈ విధానం యొక్క ముఖ్యమైన లోపాలను వెల్లడించింది:

  • అనేక డొమైన్‌ల వ్యాపార లాజిక్‌ను ఒకేసారి అమలు చేసే ప్లాట్‌ఫారమ్ సేవ వైఫల్యం యొక్క ఒకే పాయింట్‌గా గొప్ప నష్టాలను కలిగి ఉంటుంది. వ్యాపార తర్కంలో తరచుగా మార్పులు చేయడం వలన సిస్టమ్-వ్యాప్త వైఫల్యాలకు దారితీసే బగ్‌ల ప్రమాదాన్ని పెంచుతుంది;
  • పనితీరు సమస్యలు: వ్యాపార తర్కం దాని డేటాతో ఇరుకైన మరియు నెమ్మదైన ఇంటర్‌ఫేస్ ద్వారా పని చేస్తుంది:
    • డేటా మరోసారి మార్షల్ చేయబడుతుంది మరియు నెట్‌వర్క్ స్టాక్ ద్వారా పంప్ చేయబడుతుంది;
    • సేవ యొక్క బాహ్య API స్థాయిలో తగినంత ప్రశ్న పారామిటరైజేషన్ సామర్థ్యాలు లేనందున, డొమైన్ సేవ తరచుగా ప్రాసెసింగ్ కోసం అవసరమైన వ్యాపార లాజిక్ కంటే ఎక్కువ డేటాను అందిస్తుంది;
    • అనేక స్వతంత్ర వ్యాపార లాజిక్‌లు ప్రాసెసింగ్ కోసం అదే డేటాను మళ్లీ మళ్లీ అభ్యర్థించగలవు (డేటాను కాష్ చేసే సెషన్ బీన్స్‌ని జోడించడం ద్వారా మీరు ఈ సమస్యను తగ్గించవచ్చు, అయితే ఇది ఆర్కిటెక్చర్‌ను మరింత క్లిష్టతరం చేస్తుంది మరియు డేటా తాజాదనం మరియు కాష్ చెల్లుబాటుకు సంబంధించిన సమస్యలను సృష్టిస్తుంది);
  • లావాదేవీ సమస్యలు:
    • ప్లాట్‌ఫారమ్ సేవ ద్వారా నిల్వ చేయబడిన స్థిరమైన స్థితితో వ్యాపార ప్రక్రియలు డొమైన్ డేటాకు విరుద్ధంగా ఉంటాయి మరియు ఈ సమస్యను పరిష్కరించడానికి సులభమైన మార్గాలు లేవు;
    • లావాదేవీ నుండి డొమైన్ డేటా యొక్క లాక్‌ని తరలించడం: డొమైన్ వ్యాపార తర్కం మార్పులు చేయవలసి వస్తే, మొదట వాస్తవ డేటా యొక్క ఖచ్చితత్వాన్ని తనిఖీ చేసిన తర్వాత, ప్రాసెస్ చేయబడిన డేటాలో పోటీతత్వ మార్పు యొక్క అవకాశాన్ని మినహాయించడం అవసరం. డేటాను బాహ్యంగా నిరోధించడం సమస్యను పరిష్కరించడానికి సహాయపడుతుంది, అయితే అటువంటి పరిష్కారం అదనపు నష్టాలను కలిగి ఉంటుంది మరియు సిస్టమ్ యొక్క మొత్తం విశ్వసనీయతను తగ్గిస్తుంది;
  • అప్‌డేట్ చేసేటప్పుడు అదనపు చిక్కులు: కొన్ని సందర్భాల్లో, మీరు స్థిరమైన సేవ మరియు వ్యాపార తర్కాన్ని ఏకకాలంలో లేదా ఖచ్చితమైన క్రమంలో అప్‌డేట్ చేయాలి.

చివరికి, నేను బేసిక్స్‌కి తిరిగి వెళ్లవలసి వచ్చింది: డొమైన్ డేటా మరియు డొమైన్ బిజినెస్ లాజిక్‌లను ఒక మైక్రోసర్వీస్‌లో చేర్చండి. ఈ విధానం మైక్రోసర్వీస్‌ని సిస్టమ్‌లో అంతర్భాగంగా భావించడాన్ని సులభతరం చేస్తుంది మరియు పై సమస్యలకు దారితీయదు. ఇది కూడా ఉచితం కాదు:

  • వ్యాపార లాజిక్ (ముఖ్యంగా, వ్యాపార ప్రక్రియలలో భాగంగా వినియోగదారు కార్యకలాపాలను అందించడం) మరియు API ప్లాట్‌ఫారమ్ సేవలతో పరస్పర చర్య కోసం API ప్రమాణీకరణ అవసరం; API మార్పులపై మరింత జాగ్రత్తగా శ్రద్ధ వహించడం, ముందుకు మరియు వెనుకకు అనుకూలత అవసరం;
  • అటువంటి ప్రతి మైక్రోసర్వీస్‌లో భాగంగా వ్యాపార తర్కం యొక్క పనితీరును నిర్ధారించడానికి అదనపు రన్‌టైమ్ లైబ్రరీలను జోడించడం అవసరం, మరియు ఇది అటువంటి లైబ్రరీలకు కొత్త అవసరాలకు దారితీస్తుంది: తేలిక మరియు కనీస ట్రాన్సిటివ్ డిపెండెన్సీలు;
  • వ్యాపార లాజిక్ డెవలపర్లు లైబ్రరీ సంస్కరణలను ట్రాక్ చేయాలి: మైక్రోసర్వీస్ చాలా కాలం వరకు ఖరారు చేయకపోతే, అది చాలావరకు లైబ్రరీల యొక్క పాత వెర్షన్‌ను కలిగి ఉంటుంది. ఇది కొత్త ఫీచర్‌ని జోడించడానికి ఊహించని అడ్డంకి కావచ్చు మరియు సంస్కరణల మధ్య అననుకూలమైన మార్పులు ఉంటే అటువంటి సేవ యొక్క పాత వ్యాపార తర్కాన్ని లైబ్రరీల యొక్క కొత్త వెర్షన్‌లకు తరలించడం అవసరం కావచ్చు.

BPM స్టైల్ ఇంటిగ్రేషన్

అటువంటి నిర్మాణంలో ప్లాట్‌ఫారమ్ సేవల పొర కూడా ఉంది, అయితే ఈ పొర ఇకపై డొమైన్ వ్యాపార లాజిక్‌ను అమలు చేయడానికి కంటైనర్‌ను ఏర్పరుస్తుంది, కానీ దాని పర్యావరణం మాత్రమే సహాయక "ప్లాట్‌ఫారమ్" ఫంక్షన్‌లను అందిస్తుంది. ఇటువంటి పొర డొమైన్ మైక్రోసర్వీస్ యొక్క తేలికను నిర్వహించడానికి మాత్రమే కాకుండా, నిర్వహణను కేంద్రీకరించడానికి కూడా అవసరం.

ఉదాహరణకు, వ్యాపార ప్రక్రియలలో వినియోగదారు కార్యకలాపాలు టాస్క్‌లను ఉత్పత్తి చేస్తాయి. అయితే, టాస్క్‌లతో పని చేస్తున్నప్పుడు, వినియోగదారు తప్పనిసరిగా సాధారణ జాబితాలోని అన్ని డొమైన్‌ల నుండి టాస్క్‌లను చూడాలి, అంటే డొమైన్ బిజినెస్ లాజిక్ నుండి క్లియర్ చేయబడిన తగిన టాస్క్ రిజిస్ట్రేషన్ ప్లాట్‌ఫారమ్ సర్వీస్ ఉండాలి. ఈ సందర్భంలో వ్యాపార తర్కం యొక్క ఎన్‌క్యాప్సులేషన్‌ను ఉంచడం చాలా సమస్యాత్మకమైనది మరియు ఇది ఈ నిర్మాణం యొక్క మరొక రాజీ.

అప్లికేషన్ డెవలపర్ దృష్టిలో వ్యాపార ప్రక్రియల ఏకీకరణ

ఇప్పటికే పైన పేర్కొన్నట్లుగా, అప్లికేషన్ డెవలపర్ మంచి అభివృద్ధి ఉత్పాదకతను లెక్కించడానికి అనేక అనువర్తనాల పరస్పర చర్య యొక్క సాంకేతిక మరియు ఇంజనీరింగ్ లక్షణాల నుండి తప్పనిసరిగా సంగ్రహించబడాలి.

వ్యాసం కోసం ప్రత్యేకంగా కనుగొనబడిన చాలా కష్టమైన ఇంటిగ్రేషన్ సమస్యను పరిష్కరించడానికి ప్రయత్నిద్దాం. ఇది మూడు అప్లికేషన్‌లతో కూడిన "గేమ్" టాస్క్ అవుతుంది, వాటిలో ప్రతి ఒక్కటి కొన్ని డొమైన్ పేరును నిర్వచిస్తుంది: "app1", "app2", "app3".

ప్రతి అప్లికేషన్ లోపల, ఇంటిగ్రేషన్ బస్ ద్వారా "బాల్ ప్లే" ప్రారంభించే వ్యాపార ప్రక్రియలు ప్రారంభించబడతాయి. "బాల్" అనే సందేశాలు బంతిగా పని చేస్తాయి.

గేమ్ నియమాలు:

  • మొదటి ఆటగాడు ప్రారంభించేవాడు. అతను ఇతర ఆటగాళ్లను ఆటకు ఆహ్వానిస్తాడు, ఆటను ప్రారంభిస్తాడు మరియు ఏ సమయంలోనైనా ముగించవచ్చు;
  • ఇతర ఆటగాళ్ళు ఆటలో తమ భాగస్వామ్యాన్ని ప్రకటిస్తారు, ఒకరితో ఒకరు మరియు మొదటి ఆటగాడితో "పరిచయం చేసుకోండి";
  • బంతిని అందుకున్న తర్వాత, ఆటగాడు మరొక పాల్గొనే ఆటగాడిని ఎంచుకుని, అతనికి బంతిని పంపుతాడు. మొత్తం పాస్‌ల సంఖ్య లెక్కించబడుతుంది;
  • ప్రతి క్రీడాకారుడు "శక్తి"ని కలిగి ఉంటాడు, ఆ ఆటగాడు బంతిని పాస్ చేసే ప్రతిసారి అది తగ్గుతుంది. శక్తి అయిపోయినప్పుడు, ఆటగాడు ఆట నుండి తొలగించబడతాడు, అతని పదవీ విరమణ ప్రకటించాడు;
  • ఆటగాడు ఒంటరిగా ఉంటే, అతను వెంటనే తన నిష్క్రమణను ప్రకటిస్తాడు;
  • ఆటగాళ్లందరూ తొలగించబడినప్పుడు, మొదటి ఆటగాడు ఆట ముగిసినట్లు ప్రకటిస్తాడు. అతను ఆటను ముందే వదిలేస్తే, దాన్ని పూర్తి చేయడానికి ఆటను అనుసరించడం మిగిలి ఉంది.

ఈ సమస్యను పరిష్కరించడానికి, నేను వ్యాపార ప్రక్రియల కోసం మా DSLని ఉపయోగిస్తాను, ఇది కనీసం బాయిలర్‌ప్లేట్‌తో కోట్లిన్‌లోని లాజిక్‌ను కాంపాక్ట్‌గా వివరించడానికి మిమ్మల్ని అనుమతిస్తుంది.

app1 అప్లికేషన్‌లో, మొదటి ఆటగాడి వ్యాపార ప్రక్రియ (అతను గేమ్‌ని ప్రారంభించేవాడు కూడా) పని చేస్తుంది:

తరగతి ప్రారంభ ప్లేయర్

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

వ్యాపార లాజిక్‌ను అమలు చేయడంతో పాటు, పై కోడ్ వ్యాపార ప్రక్రియ యొక్క ఆబ్జెక్ట్ మోడల్‌ను రూపొందించగలదు, దానిని రేఖాచిత్రంగా చూడవచ్చు. మేము ఇంకా విజువలైజర్‌ని అమలు చేయలేదు, కాబట్టి మేము గీయడానికి కొంత సమయం వెచ్చించాల్సి వచ్చింది (పై కోడ్‌తో రేఖాచిత్రం యొక్క స్థిరత్వాన్ని మెరుగుపరచడానికి గేట్‌ల వినియోగానికి సంబంధించి ఇక్కడ నేను BPMN సంజ్ఞామానాన్ని కొద్దిగా సరళీకృతం చేసాను):

BPM స్టైల్ ఇంటిగ్రేషన్

app2 మరొక ప్లేయర్ యొక్క వ్యాపార ప్రక్రియను కలిగి ఉంటుంది:

తరగతి రాండమ్ ప్లేయర్

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

రేఖాచిత్రం:

BPM స్టైల్ ఇంటిగ్రేషన్

app3 అప్లికేషన్‌లో, మేము ప్లేయర్‌ని కొంచెం భిన్నమైన ప్రవర్తనతో తయారు చేస్తాము: యాదృచ్ఛికంగా తదుపరి ప్లేయర్‌ని ఎంచుకునే బదులు, అతను రౌండ్-రాబిన్ అల్గోరిథం ప్రకారం పని చేస్తాడు:

తరగతి 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}")
}

లేకపోతే, ఆటగాడి ప్రవర్తన మునుపటి నుండి భిన్నంగా లేదు, కాబట్టి రేఖాచిత్రం మారదు.

ఇప్పుడు అన్నింటినీ అమలు చేయడానికి మనకు ఒక పరీక్ష అవసరం. బాయిలర్‌ప్లేట్‌తో కథనాన్ని చిందరవందర చేయకుండా ఉండటానికి నేను పరీక్ష యొక్క కోడ్‌ను మాత్రమే ఇస్తాను (వాస్తవానికి, ఇతర వ్యాపార ప్రక్రియల ఏకీకరణను పరీక్షించడానికి నేను ఇంతకు ముందు సృష్టించిన పరీక్ష వాతావరణాన్ని ఉపయోగించాను):

టెస్ట్ గేమ్()

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

పరీక్షను అమలు చేయండి, లాగ్‌ను చూడండి:

కన్సోల్ అవుట్‌పుట్

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

వీటన్నింటి నుండి అనేక ముఖ్యమైన ముగింపులు తీసుకోవచ్చు:

  • అవసరమైన సాధనాలు అందుబాటులో ఉంటే, అప్లికేషన్ డెవలపర్‌లు వ్యాపార తర్కం నుండి వైదొలగకుండా అప్లికేషన్‌ల మధ్య ఏకీకరణ పరస్పర చర్యలను సృష్టించగలరు;
  • ఇంజనీరింగ్ సామర్థ్యాలు అవసరమయ్యే ఇంటిగ్రేషన్ టాస్క్ యొక్క సంక్లిష్టత (సంక్లిష్టత) ఫ్రేమ్‌వర్క్ యొక్క నిర్మాణంలో మొదట నిర్దేశించబడితే ఫ్రేమ్‌వర్క్ లోపల దాచబడుతుంది. పని యొక్క కష్టం (కష్టం) దాచబడదు, కాబట్టి కోడ్‌లోని కష్టమైన పనికి పరిష్కారం తదనుగుణంగా కనిపిస్తుంది;
  • ఇంటిగ్రేషన్ లాజిక్‌ను అభివృద్ధి చేస్తున్నప్పుడు, చివరికి స్థిరత్వం మరియు ఏకీకరణలో పాల్గొనేవారిందరి స్థితి మార్పు యొక్క సరళీకరణ లేకపోవడం పరిగణనలోకి తీసుకోవడం అవసరం. ఇది బాహ్య సంఘటనలు జరిగే క్రమంలో తర్కాన్ని క్లిష్టతరం చేయడానికి మనల్ని బలవంతం చేస్తుంది. మా ఉదాహరణలో, ఆటగాడు ఆట నుండి నిష్క్రమించినట్లు ప్రకటించిన తర్వాత ఆటలో పాల్గొనవలసి వస్తుంది: అతని నిష్క్రమణ గురించి సమాచారం చేరే వరకు మరియు పాల్గొనే వారందరూ ప్రాసెస్ చేసే వరకు ఇతర ఆటగాళ్ళు అతనికి బంతిని పంపడం కొనసాగిస్తారు. ఈ తర్కం ఆట నియమాల నుండి అనుసరించబడదు మరియు ఎంచుకున్న నిర్మాణం యొక్క ఫ్రేమ్‌వర్క్‌లో రాజీ పరిష్కారం.

తరువాత, మా పరిష్కారం, రాజీలు మరియు ఇతర అంశాల యొక్క వివిధ సూక్ష్మబేధాల గురించి మాట్లాడుదాం.

అన్ని సందేశాలు ఒకే వరుసలో ఉన్నాయి

అన్ని ఇంటిగ్రేటెడ్ అప్లికేషన్‌లు ఒక ఇంటిగ్రేషన్ బస్‌తో పని చేస్తాయి, ఇది బాహ్య బ్రోకర్‌గా ప్రదర్శించబడుతుంది, సందేశాల కోసం ఒక BPMQueue మరియు సిగ్నల్‌ల కోసం ఒక BPMTopic టాపిక్ (ఈవెంట్‌లు) ఒకే క్యూ ద్వారా అన్ని సందేశాలను పంపడం అనేది ఒక రాజీ. వ్యాపార లాజిక్ స్థాయిలో, మీరు ఇప్పుడు సిస్టమ్ నిర్మాణంలో మార్పులు చేయకుండానే మీకు కావలసినన్ని కొత్త రకాల సందేశాలను పరిచయం చేయవచ్చు. ఇది ఒక ముఖ్యమైన సరళీకరణ, కానీ ఇది కొన్ని ప్రమాదాలను కలిగి ఉంటుంది, ఇది మా సాధారణ పనుల సందర్భంలో, మాకు అంత ముఖ్యమైనది కాదు.

BPM స్టైల్ ఇంటిగ్రేషన్

అయితే, ఇక్కడ ఒక సూక్ష్మభేదం ఉంది: ప్రతి అప్లికేషన్ దాని డొమైన్ పేరు ద్వారా ప్రవేశ ద్వారం వద్ద క్యూ నుండి "దాని" సందేశాలను ఫిల్టర్ చేస్తుంది. అలాగే, మీరు సిగ్నల్ యొక్క “పరిధిని” ఒకే అప్లికేషన్‌కు పరిమితం చేయవలసి వస్తే, డొమైన్‌ను సిగ్నల్‌లలో పేర్కొనవచ్చు. ఇది బస్సు యొక్క బ్యాండ్‌విడ్త్‌ను పెంచాలి, అయితే వ్యాపార తర్కం ఇప్పుడు డొమైన్ పేర్లతో పనిచేయాలి: సందేశాలను సంబోధించడానికి తప్పనిసరి, సిగ్నల్‌లకు కావాల్సినది.

ఇంటిగ్రేషన్ బస్ యొక్క విశ్వసనీయతను నిర్ధారించడం

విశ్వసనీయత అనేక అంశాలతో రూపొందించబడింది:

  • ఎంచుకున్న మెసేజ్ బ్రోకర్ ఆర్కిటెక్చర్‌లో కీలకమైన భాగం మరియు వైఫల్యం యొక్క ఒకే పాయింట్: ఇది తప్పక తగినంత తప్పును తట్టుకునేలా ఉండాలి. మీరు మంచి మద్దతు మరియు పెద్ద సంఘంతో సమయ-పరీక్షించిన అమలులను మాత్రమే ఉపయోగించాలి;
  • మెసేజ్ బ్రోకర్ యొక్క అధిక లభ్యతను నిర్ధారించడం అవసరం, దీని కోసం అది ఏకీకృత అప్లికేషన్‌ల నుండి భౌతికంగా వేరు చేయబడాలి (అనువర్తిత వ్యాపార తర్కంతో అప్లికేషన్‌ల యొక్క అధిక లభ్యత అందించడం చాలా కష్టం మరియు ఖరీదైనది);
  • బ్రోకర్ "కనీసం ఒక్కసారి" డెలివరీ హామీలను అందించడానికి బాధ్యత వహిస్తాడు. ఇంటిగ్రేషన్ బస్ యొక్క నమ్మకమైన ఆపరేషన్ కోసం ఇది తప్పనిసరి అవసరం. "సరిగ్గా ఒకసారి" స్థాయి హామీలు అవసరం లేదు: వ్యాపార ప్రక్రియలు సాధారణంగా సందేశాలు లేదా ఈవెంట్‌ల పునరావృత స్వీకరణకు సున్నితంగా ఉండవు మరియు ఇది ముఖ్యమైన ప్రత్యేక పనులలో, వ్యాపార లాజిక్‌కు నిరంతరం ఉపయోగించడం కంటే అదనపు తనిఖీలను జోడించడం సులభం. "ఖరీదైన" "గ్యారంటీలు;
  • సందేశాలు మరియు సంకేతాలను పంపడం అనేది వ్యాపార ప్రక్రియలు మరియు డొమైన్ డేటా యొక్క స్థితిలో మార్పుతో ఒక సాధారణ లావాదేవీలో తప్పనిసరిగా పాల్గొనాలి. నమూనాను ఉపయోగించడం ప్రాధాన్యత ఎంపిక లావాదేవీ అవుట్‌బాక్స్, కానీ దీనికి డేటాబేస్లో అదనపు పట్టిక మరియు రిలే అవసరం. JEE అప్లికేషన్‌లలో, స్థానిక JTA మేనేజర్‌ని ఉపయోగించడం ద్వారా దీన్ని సులభతరం చేయవచ్చు, కానీ ఎంచుకున్న బ్రోకర్‌కి కనెక్షన్ తప్పనిసరిగా మోడ్‌లో పని చేయగలగాలి XA;
  • ఇన్‌కమింగ్ సందేశాలు మరియు ఈవెంట్‌ల హ్యాండ్లర్లు వ్యాపార ప్రక్రియ యొక్క స్థితిని మార్చే లావాదేవీతో కూడా పని చేయాలి: అటువంటి లావాదేవీని వెనక్కి తీసుకుంటే, సందేశం యొక్క రసీదు కూడా రద్దు చేయబడాలి;
  • లోపాల కారణంగా బట్వాడా చేయలేని సందేశాలను ప్రత్యేక స్టోర్‌లో నిల్వ చేయాలి డి.ఎల్.క్యూ. (డెడ్ లెటర్ క్యూ). దీన్ని చేయడానికి, మేము అటువంటి సందేశాలను దాని నిల్వలో నిల్వ చేసే ప్రత్యేక ప్లాట్‌ఫారమ్ మైక్రోసర్వీస్‌ని సృష్టించాము, వాటిని లక్షణాల ద్వారా సూచిక చేస్తాము (త్వరిత సమూహనం మరియు శోధన కోసం), మరియు వీక్షించడానికి, గమ్యస్థాన చిరునామాకు మళ్లీ పంపడానికి మరియు సందేశాలను తొలగించడానికి APIని బహిర్గతం చేస్తాము. సిస్టమ్ నిర్వాహకులు వారి వెబ్ ఇంటర్‌ఫేస్ ద్వారా ఈ సేవతో పని చేయవచ్చు;
  • బ్రోకర్ సెట్టింగ్‌లలో, DLQలోకి సందేశాలు వచ్చే అవకాశాన్ని తగ్గించడానికి మీరు డెలివరీ రీట్రీలు మరియు డెలివరీల మధ్య జాప్యాల సంఖ్యను సర్దుబాటు చేయాలి (ఆప్టిమల్ పారామితులను లెక్కించడం దాదాపు అసాధ్యం, కానీ మీరు అనుభవపూర్వకంగా పని చేయవచ్చు మరియు వాటిని సర్దుబాటు చేయవచ్చు ఆపరేషన్);
  • DLQ స్టోర్ నిరంతరం పర్యవేక్షించబడాలి మరియు మానిటరింగ్ సిస్టమ్ సిస్టమ్ నిర్వాహకులకు తెలియజేయాలి, తద్వారా వారు పంపబడని సందేశాలు సంభవించినప్పుడు వీలైనంత త్వరగా ప్రతిస్పందించగలరు. ఇది వైఫల్యం లేదా వ్యాపార లాజిక్ లోపం యొక్క "నష్టం జోన్"ని తగ్గిస్తుంది;
  • అనువర్తనాల యొక్క తాత్కాలిక లేకపోవడం పట్ల ఇంటిగ్రేషన్ బస్ తప్పనిసరిగా సున్నితంగా ఉండాలి: టాపిక్ సబ్‌స్క్రిప్షన్‌లు మన్నికైనవిగా ఉండాలి మరియు అప్లికేషన్ యొక్క డొమైన్ పేరు ప్రత్యేకంగా ఉండాలి, తద్వారా అప్లికేషన్ లేనప్పుడు క్యూ నుండి మరొకరు దాని సందేశాన్ని ప్రాసెస్ చేయడానికి ప్రయత్నించరు.

వ్యాపార తర్కం యొక్క థ్రెడ్ భద్రతను నిర్ధారించడం

వ్యాపార ప్రక్రియ యొక్క అదే ఉదాహరణ ఒకేసారి అనేక సందేశాలు మరియు ఈవెంట్‌లను స్వీకరించగలదు, దీని ప్రాసెసింగ్ సమాంతరంగా ప్రారంభమవుతుంది. అదే సమయంలో, అప్లికేషన్ డెవలపర్ కోసం, ప్రతిదీ సరళంగా మరియు థ్రెడ్-సురక్షితంగా ఉండాలి.

ఈ వ్యాపార ప్రక్రియను వ్యక్తిగతంగా ప్రభావితం చేసే ప్రతి బాహ్య ఈవెంట్‌ను ప్రాసెస్ బిజినెస్ లాజిక్ ప్రాసెస్ చేస్తుంది. ఈ సంఘటనలు కావచ్చు:

  • వ్యాపార ప్రక్రియ ఉదాహరణను ప్రారంభించడం;
  • వ్యాపార ప్రక్రియలో కార్యాచరణకు సంబంధించిన వినియోగదారు చర్య;
  • వ్యాపార ప్రక్రియ ఉదాహరణ చందా చేయబడిన సందేశం లేదా సిగ్నల్ యొక్క రసీదు;
  • వ్యాపార ప్రక్రియ ఉదాహరణ ద్వారా సెట్ చేయబడిన టైమర్ గడువు;
  • API ద్వారా నియంత్రణ చర్య (ఉదా. ప్రక్రియ రద్దు).

అటువంటి ప్రతి సంఘటన వ్యాపార ప్రక్రియ యొక్క స్థితిని మార్చగలదు: కొన్ని కార్యకలాపాలు ముగియవచ్చు మరియు మరికొన్ని ప్రారంభించవచ్చు, స్థిరమైన లక్షణాల విలువలు మారవచ్చు. ఏదైనా కార్యకలాపాన్ని మూసివేయడం వలన కింది కార్యకలాపాలలో ఒకటి లేదా అంతకంటే ఎక్కువ సక్రియం కావచ్చు. వారు, ఇతర ఈవెంట్‌ల కోసం వేచి ఉండడాన్ని ఆపివేయవచ్చు లేదా వారికి అదనపు డేటా అవసరం లేకపోతే, అదే లావాదేవీని పూర్తి చేయవచ్చు. లావాదేవీని ముగించే ముందు, వ్యాపార ప్రక్రియ యొక్క కొత్త స్థితి డేటాబేస్‌లో నిల్వ చేయబడుతుంది, ఇక్కడ అది తదుపరి బాహ్య ఈవెంట్ కోసం వేచి ఉంటుంది.

అప్‌డేట్ కోసం ఎంపికను ఉపయోగిస్తున్నప్పుడు రిలేషనల్ డేటాబేస్‌లో నిల్వ చేయబడిన నిరంతర వ్యాపార ప్రక్రియ డేటా చాలా అనుకూలమైన ప్రాసెసింగ్ సింక్రొనైజేషన్ పాయింట్. ఒక లావాదేవీ దానిని మార్చడానికి వ్యాపార ప్రక్రియ యొక్క స్థితిని ఆధారం నుండి పొందగలిగితే, సమాంతరంగా ఏ ఇతర లావాదేవీ మరొక మార్పు కోసం అదే స్థితిని పొందలేరు మరియు మొదటి లావాదేవీ పూర్తయిన తర్వాత, రెండవది ఇప్పటికే మారిన స్థితిని అందుకుంటామని హామీ ఇచ్చారు.

DBMS వైపు నిరాశావాద తాళాలను ఉపయోగించి, మేము అవసరమైన అన్ని అవసరాలను పూర్తి చేస్తాము ACID, మరియు నడుస్తున్న సందర్భాల సంఖ్యను పెంచడం ద్వారా వ్యాపార లాజిక్‌తో అప్లికేషన్‌ను స్కేల్ చేసే సామర్థ్యాన్ని కూడా కలిగి ఉంటుంది.

అయితే, నిరాశావాద తాళాలు డెడ్‌లాక్‌లతో మనల్ని బెదిరిస్తాయి, అంటే వ్యాపార తర్కంలోని కొన్ని దారుణమైన కేసుల్లో డెడ్‌లాక్‌ల విషయంలో అప్‌డేట్ కోసం ఎంపిక చేయడం ఇప్పటికీ కొంత సహేతుకమైన గడువుకు పరిమితం చేయబడాలి.

మరొక సమస్య వ్యాపార ప్రక్రియ ప్రారంభం యొక్క సమకాలీకరణ. వ్యాపార ప్రక్రియ ఉదాహరణ లేనప్పటికీ, డేటాబేస్‌లో స్థితి లేదు, కాబట్టి వివరించిన పద్ధతి పనిచేయదు. మీరు నిర్దిష్ట స్కోప్‌లో వ్యాపార ప్రక్రియ ఉదాహరణ యొక్క ప్రత్యేకతను నిర్ధారించాలనుకుంటే, మీకు ప్రాసెస్ క్లాస్ మరియు సంబంధిత స్కోప్‌తో అనుబంధించబడిన ఒక రకమైన సమకాలీకరణ వస్తువు అవసరం. ఈ సమస్యను పరిష్కరించడానికి, బాహ్య సేవ ద్వారా URI ఫార్మాట్‌లోని కీ ద్వారా నిర్దేశించబడిన ఏకపక్ష వనరుపై లాక్‌ని తీయడానికి మేము వేరొక లాకింగ్ మెకానిజంను ఉపయోగిస్తాము.

మా ఉదాహరణలలో, InitialPlayer వ్యాపార ప్రక్రియ డిక్లరేషన్‌ను కలిగి ఉంది

uniqueConstraint = UniqueConstraints.singleton

అందువల్ల, లాగ్ సంబంధిత కీ యొక్క లాక్‌ని తీసుకోవడం మరియు విడుదల చేయడం గురించి సందేశాలను కలిగి ఉంటుంది. ఇతర వ్యాపార ప్రక్రియల కోసం అలాంటి సందేశాలు ఏవీ లేవు: ఏకైక నియంత్రణ సెట్ చేయబడలేదు.

స్థిరమైన స్థితితో వ్యాపార ప్రక్రియ సమస్యలు

కొన్నిసార్లు స్థిరమైన స్థితిని కలిగి ఉండటం సహాయపడటమే కాకుండా, నిజంగా అభివృద్ధికి ఆటంకం కలిగిస్తుంది.
మీరు వ్యాపార తర్కం మరియు / లేదా వ్యాపార ప్రక్రియ నమూనాలో మార్పులు చేయవలసి వచ్చినప్పుడు సమస్యలు మొదలవుతాయి. అటువంటి మార్పు ఏదీ వ్యాపార ప్రక్రియల పాత స్థితికి అనుకూలంగా ఉన్నట్లు కనుగొనబడలేదు. డేటాబేస్లో అనేక "ప్రత్యక్ష" ఉదాహరణలు ఉన్నట్లయితే, అననుకూలమైన మార్పులను చేయడం చాలా ఇబ్బందిని కలిగిస్తుంది, ఇది jBPMని ఉపయోగిస్తున్నప్పుడు మేము తరచుగా ఎదుర్కొంటాము.

మార్పు యొక్క లోతుపై ఆధారపడి, మీరు రెండు విధాలుగా పని చేయవచ్చు:

  1. పాతదానికి అననుకూలమైన మార్పులను చేయకుండా కొత్త రకమైన వ్యాపార ప్రక్రియను సృష్టించండి మరియు కొత్త సందర్భాలను ప్రారంభించేటప్పుడు పాత దానికి బదులుగా దాన్ని ఉపయోగించండి. పాత సందర్భాలు "పాత మార్గంలో" పని చేస్తూనే ఉంటాయి;
  2. వ్యాపార లాజిక్‌ని అప్‌డేట్ చేస్తున్నప్పుడు వ్యాపార ప్రక్రియల యొక్క స్థిరమైన స్థితిని మార్చండి.

మొదటి మార్గం సరళమైనది, కానీ దాని పరిమితులు మరియు అప్రయోజనాలు ఉన్నాయి, ఉదాహరణకు:

  • అనేక వ్యాపార ప్రక్రియ నమూనాలలో వ్యాపార తర్కం యొక్క నకిలీ, వ్యాపార తర్కం యొక్క పరిమాణంలో పెరుగుదల;
  • తరచుగా కొత్త వ్యాపార తర్కానికి తక్షణ మార్పు అవసరం (దాదాపు ఎల్లప్పుడూ ఏకీకరణ పనుల పరంగా);
  • వాడుకలో లేని మోడల్‌లను తొలగించడం ఏ సమయంలో సాధ్యమో డెవలపర్‌కు తెలియదు.

ఆచరణలో, మేము రెండు విధానాలను ఉపయోగిస్తాము, కానీ మా జీవితాలను సరళీకృతం చేయడానికి అనేక నిర్ణయాలు తీసుకున్నాము:

  • డేటాబేస్‌లో, వ్యాపార ప్రక్రియ యొక్క స్థిరమైన స్థితి సులభంగా చదవగలిగే మరియు సులభంగా ప్రాసెస్ చేయబడిన రూపంలో నిల్వ చేయబడుతుంది: JSON ఫార్మాట్ స్ట్రింగ్‌లో. ఇది అప్లికేషన్ లోపల మరియు వెలుపల మైగ్రేషన్‌లను నిర్వహించడానికి మిమ్మల్ని అనుమతిస్తుంది. తీవ్రమైన సందర్భాల్లో, మీరు దీన్ని హ్యాండిల్స్‌తో కూడా సర్దుబాటు చేయవచ్చు (డీబగ్గింగ్ సమయంలో అభివృద్ధిలో ప్రత్యేకంగా ఉపయోగపడుతుంది);
  • ఇంటిగ్రేషన్ బిజినెస్ లాజిక్ వ్యాపార ప్రక్రియల పేర్లను ఉపయోగించదు, తద్వారా ఏ సమయంలోనైనా పాల్గొనే ప్రక్రియలలో ఒకదానిని కొత్త పేరుతో కొత్త పేరుతో భర్తీ చేయడం సాధ్యమవుతుంది (ఉదాహరణకు, "InitialPlayerV2"). సందేశాలు మరియు సంకేతాల పేర్ల ద్వారా బైండింగ్ జరుగుతుంది;
  • ప్రాసెస్ మోడల్ వెర్షన్ నంబర్‌ను కలిగి ఉంది, మేము ఈ మోడల్‌కు అననుకూలమైన మార్పులు చేస్తే దాన్ని పెంచుతాము మరియు ఈ సంఖ్య ప్రాసెస్ ఇన్‌స్టాన్స్ స్థితితో పాటు నిల్వ చేయబడుతుంది;
  • ప్రక్రియ యొక్క స్థిరమైన స్థితి మొదట బేస్ నుండి అనుకూలమైన ఆబ్జెక్ట్ మోడల్‌లోకి చదవబడుతుంది, ఇది మోడల్ యొక్క సంస్కరణ సంఖ్య మారినట్లయితే మైగ్రేషన్ విధానం పని చేస్తుంది;
  • మైగ్రేషన్ విధానం వ్యాపార తర్కం పక్కన ఉంచబడుతుంది మరియు డేటాబేస్ నుండి దాని పునరుద్ధరణ సమయంలో వ్యాపార ప్రక్రియ యొక్క ప్రతి ఉదాహరణకి "సోమరితనం" అని పిలుస్తారు;
  • మీరు అన్ని ప్రాసెస్ ఇన్‌స్టాన్స్‌ల స్థితిని త్వరగా మరియు సమకాలీకరించవలసి వస్తే, మరిన్ని క్లాసిక్ డేటాబేస్ మైగ్రేషన్ సొల్యూషన్స్ ఉపయోగించబడతాయి, కానీ మీరు అక్కడ JSONతో పని చేయాలి.

వ్యాపార ప్రక్రియల కోసం నాకు మరొక ఫ్రేమ్‌వర్క్ అవసరమా?

వ్యాసంలో వివరించిన పరిష్కారాలు మా జీవితాలను గణనీయంగా సరళీకృతం చేయడానికి, అప్లికేషన్ అభివృద్ధి స్థాయిలో పరిష్కరించబడిన సమస్యల పరిధిని విస్తరించడానికి మరియు మైక్రోసర్వీస్‌లుగా వ్యాపార తర్కాన్ని వేరు చేసే ఆలోచనను మరింత ఆకర్షణీయంగా మార్చడానికి మాకు అనుమతినిచ్చాయి. దీని కోసం, చాలా పని జరిగింది, వ్యాపార ప్రక్రియల కోసం చాలా “తేలికపాటి” ఫ్రేమ్‌వర్క్ సృష్టించబడింది, అలాగే విస్తృత శ్రేణి అనువర్తిత పనుల సందర్భంలో గుర్తించబడిన సమస్యలను పరిష్కరించడానికి సేవా భాగాలు. ఉచిత లైసెన్స్ క్రింద సాధారణ భాగాల అభివృద్ధిని ఓపెన్ యాక్సెస్‌లోకి తీసుకురావడానికి, ఈ ఫలితాలను భాగస్వామ్యం చేయాలనే కోరిక మాకు ఉంది. దీనికి కొంత ప్రయత్నం మరియు సమయం అవసరం. అటువంటి పరిష్కారాల కోసం డిమాండ్‌ను అర్థం చేసుకోవడం మాకు అదనపు ప్రోత్సాహకంగా ఉంటుంది. ప్రతిపాదిత వ్యాసంలో, ఫ్రేమ్‌వర్క్ యొక్క సామర్థ్యాలకు చాలా తక్కువ శ్రద్ధ ఇవ్వబడుతుంది, అయితే వాటిలో కొన్ని సమర్పించబడిన ఉదాహరణల నుండి కనిపిస్తాయి. అయినప్పటికీ మేము మా ఫ్రేమ్‌వర్క్‌ను ప్రచురిస్తే, ప్రత్యేక కథనం దానికి అంకితం చేయబడుతుంది. ఈలోగా, మీరు ప్రశ్నకు సమాధానం ఇవ్వడం ద్వారా కొంచెం అభిప్రాయాన్ని తెలియజేస్తే మేము కృతజ్ఞులమై ఉంటాము:

నమోదు చేసుకున్న వినియోగదారులు మాత్రమే సర్వేలో పాల్గొనగలరు. సైన్ ఇన్ చేయండిదయచేసి.

వ్యాపార ప్రక్రియల కోసం నాకు మరొక ఫ్రేమ్‌వర్క్ అవసరమా?

  • 18,8%అవును, నేను చాలా కాలంగా ఇలాంటి వాటి కోసం వెతుకుతున్నాను.

  • 12,5%మీ అమలు గురించి మరింత తెలుసుకోవడం ఆసక్తికరంగా ఉంటుంది, ఇది ఉపయోగకరంగా ఉండవచ్చు2

  • 6,2%మేము ఇప్పటికే ఉన్న ఫ్రేమ్‌వర్క్‌లలో ఒకదాన్ని ఉపయోగిస్తాము, కానీ మేము దానిని భర్తీ చేయడం గురించి ఆలోచిస్తున్నాము1

  • 18,8%మేము ఇప్పటికే ఉన్న ఫ్రేమ్‌వర్క్‌లలో ఒకదాన్ని ఉపయోగిస్తాము, ప్రతిదీ సూట్‌లు3

  • 18,8%ఫ్రేమ్‌వర్క్ లేకుండా ఎదుర్కోవడం 3

  • 25,0%మీ స్వంతంగా వ్రాయండి4

16 మంది వినియోగదారులు ఓటు వేశారు. 7 మంది వినియోగదారులు దూరంగా ఉన్నారు.

మూలం: www.habr.com

ఒక వ్యాఖ్యను జోడించండి