BPM ශෛලිය ඒකාබද්ධ කිරීම

BPM ශෛලිය ඒකාබද්ධ කිරීම

හායි හබ්ර්!

අපගේ සමාගම ERP පන්තියේ මෘදුකාංග විසඳුම් සංවර්ධනය සඳහා විශේෂීකරණය කරයි, එහි සිංහයාගේ කොටස විශාල ව්‍යාපාරික තර්කනය සහ EDMS කාර්ය ප්‍රවාහය සමඟ ගනුදෙනු පද්ධති විසින් අත්පත් කරගෙන ඇත. අපගේ නිෂ්පාදනවල නවීන අනුවාද JavaEE තාක්ෂණයන් මත පදනම් වේ, නමුත් අපි ක්ෂුද්‍ර සේවා සමඟ සක්‍රියව අත්හදා බලමින් සිටිමු. එවැනි විසඳුම්වල වඩාත් ගැටලුකාරී ක්ෂේත්රවලින් එකක් වන්නේ යාබද වසම්වලට සම්බන්ධ විවිධ උප පද්ධති ඒකාබද්ධ කිරීමයි. අප භාවිතා කරන වාස්තු විද්‍යාත්මක ශෛලීන්, තාක්‍ෂණ ගොඩවල් සහ රාමු කුමක් වුවත් ඒකාබද්ධතා කාර්යයන් සැමවිටම අපට විශාල හිසරදයක් ලබා දී ඇත, නමුත් මෑතකදී එවැනි ගැටළු විසඳීමේ ප්‍රගතියක් දක්නට ලැබේ.

ඔබේ අවධානයට යොමු කරන ලද ලිපියෙහි, මම නම් කරන ලද ප්රදේශයේ NPO Krista හි අත්දැකීම් සහ වාස්තුවිද්යාත්මක පර්යේෂණ ගැන කතා කරමි. යෙදුම් සංවර්ධකයෙකුගේ දෘෂ්ටි කෝණයෙන් ඒකාබද්ධ කිරීමේ ගැටලුවකට සරල විසඳුමක් පිළිබඳ උදාහරණයක් අපි සලකා බලමු, මෙම සරල බව පිටුපස සැඟවී ඇත්තේ කුමක්දැයි සොයා බලමු.

වියාචනය

ලිපියේ විස්තර කර ඇති වාස්තුවිද්යාත්මක සහ තාක්ෂණික විසඳුම් විශේෂිත කාර්යයන් සන්දර්භය තුළ පුද්ගලික අත්දැකීම් මත පදනම්ව මා විසින් ඉදිරිපත් කරනු ලැබේ. මෙම විසඳුම් විශ්වීය යැයි නොකියන අතර වෙනත් භාවිතයේ කොන්දේසි යටතේ ප්‍රශස්ත නොවිය හැක.

BPM එකට මොකද කරන්නේ?

මෙම ප්‍රශ්නයට පිළිතුරු සැපයීම සඳහා, අපගේ විසඳුම්වල ව්‍යවහාරික ගැටළු වල විශේෂතා ගැන ටිකක් සොයා බැලිය යුතුය. අපගේ සාමාන්‍ය ගණුදෙණු පද්ධතියේ ව්‍යාපාරික තර්කනයේ ප්‍රධාන කොටස වන්නේ පරිශීලක අතුරුමුහුණත් හරහා දත්ත ගබඩාවට දත්ත ඇතුළත් කිරීම, මෙම දත්ත අතින් සහ ස්වයංක්‍රීයව පරීක්ෂා කිරීම, යම් කාර්ය ප්‍රවාහයක් හරහා එය යැවීම, වෙනත් පද්ධතියකට / විශ්ලේෂණාත්මක දත්ත ගබඩාවකට / ලේඛනාගාරයකට ප්‍රකාශ කිරීම, වාර්තා උත්පාදනය කිරීම ය. මේ අනුව, පාරිභෝගිකයින් සඳහා පද්ධතියේ ප්රධාන කාර්යය වන්නේ ඔවුන්ගේ අභ්යන්තර ව්යාපාර ක්රියාවලීන්ගේ ස්වයංක්රීයකරණයයි.

පහසුව සඳහා, අපි සන්නිවේදනයේ දී "ලේඛනය" යන යෙදුම භාවිතා කරන්නේ, විශේෂිත කාර්ය ප්‍රවාහයක් "ඇමිණීම" කළ හැකි, පොදු යතුරකින් ඒකාබද්ධ වූ, දත්ත කට්ටලයක යම් සාරාංශයක් ලෙස ය.
නමුත් ඒකාබද්ධතා තර්කනය ගැන කුමක් කිව හැකිද? සියල්ලට පසු, ඒකාබද්ධ කිරීමේ කාර්යය ජනනය කරනු ලබන්නේ පද්ධතියේ ගෘහ නිර්මාණ ශිල්පය මගිනි, එය කොටස් වලට “කියන්නේ” පාරිභෝගිකයාගේ ඉල්ලීම පරිදි නොව සම්පූර්ණයෙන්ම වෙනස් සාධකවල බලපෑම යටතේ ය:

  • කොන්වේ නීතියේ බලපෑම යටතේ;
  • වෙනත් නිෂ්පාදන සඳහා කලින් සංවර්ධනය කරන ලද උප පද්ධති නැවත භාවිතා කිරීමේ ප්රතිඵලයක් ලෙස;
  • ගෘහ නිර්මාණ ශිල්පියා විසින් තීරණය කරන ලද පරිදි, ක්රියාකාරී නොවන අවශ්යතා මත පදනම්ව.

ප්‍රධාන කාර්ය ප්‍රවාහයේ ව්‍යාපාරික තර්කයෙන් ඒකාබද්ධතා තර්කනය වෙන් කිරීමට විශාල පෙළඹවීමක් ඇත, එමඟින් ව්‍යාපාර තර්කනය ඒකාබද්ධ කෞතුක වස්තු වලින් දූෂණය නොකිරීමට සහ යෙදුම් සංවර්ධකයා පද්ධතියේ වාස්තු විද්‍යාත්මක භූ දර්ශනයේ සුවිශේෂතා සොයා බැලීමෙන් ආරක්ෂා කරයි. මෙම ප්රවේශය වාසි ගණනාවක් ඇත, නමුත් ප්රායෝගිකව එහි අකාර්යක්ෂමතාව පෙන්නුම් කරයි:

  • ඒකාබද්ධ කිරීමේ ගැටළු විසඳීම සාමාන්‍යයෙන් ප්‍රධාන කාර්ය ප්‍රවාහය ක්‍රියාත්මක කිරීමේදී සීමිත විස්තාරණ ලක්ෂ්‍යයන් හේතුවෙන් සමමුහුර්ත ඇමතුම් ආකාරයෙන් සරලම විකල්පයන් වෙත ලිස්සා යයි (පහත සමමුහුර්ත ඒකාබද්ධතාවයේ අඩුපාඩු පිළිබඳ වැඩි විස්තර);
  • වෙනත් උප පද්ධතියකින් ප්‍රතිපෝෂණ අවශ්‍ය වූ විට ඒකාබද්ධ කෞතුක වස්තු තවමත් ප්‍රධාන ව්‍යාපාරික තර්කනය විනිවිද යයි;
  • යෙදුම් සංවර්ධකයා ඒකාබද්ධ කිරීම නොසලකා හරින අතර කාර්ය ප්‍රවාහය වෙනස් කිරීමෙන් එය පහසුවෙන් බිඳ දැමිය හැකිය;
  • පරිශීලකයාගේ දෘෂ්ටි කෝණයෙන් පද්ධතිය තනි සමස්තයක් වීම නවත්වයි, උප පද්ධති අතර "මැහුම්" කැපී පෙනේ, අතිරික්ත පරිශීලක මෙහෙයුම් දිස්වන අතර එමඟින් එක් උප පද්ධතියකින් තවත් උප පද්ධතියකට දත්ත මාරු කිරීම ආරම්භ කරයි.

තවත් ප්‍රවේශයක් වන්නේ මූලික ව්‍යාපාර තර්කනයේ සහ කාර්ය ප්‍රවාහයේ අනිවාර්ය අංගයක් ලෙස ඒකාබද්ධ අන්තර්ක්‍රියා සලකා බැලීමයි. යෙදුම් සංවර්ධකයින්ගේ කුසලතා අවශ්‍යතා අහස උසට නැඟීමෙන් වළක්වා ගැනීම සඳහා, විසඳුමක් තෝරාගැනීම සඳහා අවම විකල්ප සමඟින්, නව ඒකාබද්ධතා අන්තර්ක්‍රියා නිර්මාණය කිරීම පහසුවෙන් සහ ස්වභාවිකව සිදු කළ යුතුය. මෙය පෙනෙන ආකාරයට වඩා දුෂ්කර ය: මෙවලම පරිශීලකයාට එහි භාවිතය සඳහා අවශ්‍ය විවිධ විකල්ප ලබා දීමට තරම් බලවත් විය යුතු අතර ඒ සමඟම පාදයට වෙඩි තැබීමට ඉඩ නොදේ. ඒකාබද්ධතා කාර්යයන් සම්බන්ධයෙන් ඉංජිනේරුවෙකු පිළිතුරු දිය යුතු බොහෝ ප්‍රශ්න ඇත, නමුත් යෙදුම් සංවර්ධකයෙකු තම දෛනික වැඩ කටයුතුවලදී නොසිතිය යුතු ප්‍රශ්න: ගනුදෙනු සීමාවන්, අනුකූලතාව, පරමාණුකත්වය, ආරක්ෂාව, පරිමාණය, පැටවීම සහ සම්පත් බෙදා හැරීම, මාර්ගගත කිරීම, මාෂල් කිරීම, ප්‍රචාරණය සහ සන්දර්භ මාරු කිරීම යනාදිය. යෙදුම් සංවර්ධකයින්ට එවැනි ප්‍රශ්න සියල්ලටම පිළිතුරු සඟවා ඇති තරමක් සරල තීරණ සැකිලි පිරිනැමීම අවශ්‍ය වේ. මෙම රටා ප්‍රමාණවත් තරම් ආරක්ෂිත විය යුතුය: ව්‍යාපාර තර්කනය බොහෝ විට වෙනස් වන අතර එමඟින් දෝෂ හඳුන්වාදීමේ අවදානම වැඩි කරයි, දෝෂවල පිරිවැය තරමක් අඩු මට්ටමක පැවතිය යුතුය.

නමුත් තවමත්, BPM එය සමඟ ඇති සම්බන්ධය කුමක්ද? කාර්ය ප්රවාහය ක්රියාත්මක කිරීම සඳහා බොහෝ විකල්ප තිබේ ...
ඇත්ත වශයෙන්ම, ව්‍යාපාර ක්‍රියාවලි තවත් ක්‍රියාත්මක කිරීමක් අපගේ විසඳුම් තුළ ඉතා ජනප්‍රිය වේ - රාජ්‍ය සංක්‍රාන්ති රූප සටහනේ ප්‍රකාශන සැකසුම හරහා සහ ව්‍යාපාර තර්කනය සමඟ හසුරුවන්නන් සංක්‍රාන්තිවලට සම්බන්ධ කිරීම හරහා. ඒ අතරම, ව්‍යාපාර ක්‍රියාවලියේ "ලේඛනයේ" වත්මන් තත්ත්වය තීරණය කරන රාජ්‍යය "ලේඛනයේ"ම ගුණාංගයකි.

BPM ශෛලිය ඒකාබද්ධ කිරීම
ව්‍යාපෘතියේ ආරම්භයේ ක්‍රියාවලිය පෙනෙන්නේ එලෙසයි

එවැනි ක්රියාත්මක කිරීමක ජනප්රියත්වය රේඛීය ව්යාපාර ක්රියාවලීන් නිර්මාණය කිරීමේ සාපේක්ෂ සරල බව සහ වේගය නිසාය. කෙසේ වෙතත්, මෘදුකාංග පද්ධති වඩාත් සංකීර්ණ වන විට, ව්‍යාපාර ක්‍රියාවලියේ ස්වයංක්‍රීය කොටස වර්ධනය වන අතර වඩාත් සංකීර්ණ වේ. එක් එක් ශාඛාව සමාන්තරව ක්‍රියාත්මක වන පරිදි වියෝජනය, ක්‍රියාවලි කොටස් නැවත භාවිතා කිරීම මෙන්ම දෙබලක ක්‍රියාවලි අවශ්‍ය වේ. එවැනි තත්වයන් යටතේ, මෙවලම අපහසුතාවයට පත් වන අතර, රාජ්ය සංක්රාන්ති රූප සටහන එහි තොරතුරු අන්තර්ගතය අහිමි වේ (ඒකාබද්ධ අන්තර්ක්රියා රූප සටහනෙහි කිසිසේත් පිළිබිඹු නොවේ).

BPM ශෛලිය ඒකාබද්ධ කිරීම
අවශ්‍යතා පැහැදිලි කිරීමේ පුනරාවර්තන කිහිපයකින් පසු ක්‍රියාවලිය පෙනෙන්නේ මෙයයි

මෙම තත්වයෙන් මිදීමට මාර්ගය වූයේ එන්ජිම ඒකාබද්ධ කිරීමයි jBPM වඩාත් සංකීර්ණ ව්‍යාපාරික ක්‍රියාවලි සහිත සමහර නිෂ්පාදන වලට. කෙටි කාලීනව, මෙම විසඳුම යම් සාර්ථකත්වයක් ලබා ඇත: අංකනයෙහි තරමක් තොරතුරු සහ යාවත්කාලීන රූප සටහනක් පවත්වා ගනිමින් සංකීර්ණ ව්‍යාපාරික ක්‍රියාවලීන් ක්‍රියාත්මක කිරීමට හැකි විය. BPMN2.

BPM ශෛලිය ඒකාබද්ධ කිරීම
සංකීර්ණ ව්‍යාපාරික ක්‍රියාවලියක කුඩා කොටසක්

දිගුකාලීනව, විසඳුම අපේක්ෂාවන්ට අනුව ජීවත් නොවීය: දෘශ්‍ය මෙවලම් හරහා ව්‍යාපාරික ක්‍රියාවලීන් නිර්මාණය කිරීමේ ඉහළ ශ්‍රම තීව්‍රතාවය පිළිගත හැකි ඵලදායිතා දර්ශක සාක්ෂාත් කර ගැනීමට ඉඩ නොදුන් අතර, මෙවලමම සංවර්ධකයින් අතර වඩාත්ම අකමැති එකක් බවට පත්විය. බොහෝ "පැච්" සහ "කිහිලිකරු" පෙනුමට තුඩු දුන් එන්ජිමේ අභ්යන්තර ව්යුහය පිළිබඳ පැමිණිලි ද විය.

jBPM භාවිතා කිරීමේ ප්‍රධාන ධනාත්මක අංගය වූයේ ව්‍යාපාරික ක්‍රියාවලි අවස්ථාවක් සඳහා ස්වකීය ස්ථීර රාජ්‍යයක් තිබීමේ ප්‍රතිලාභ සහ හානිය අවබෝධ කර ගැනීමයි. සංඥා සහ පණිවිඩ හරහා අසමමුහුර්ත අන්තර්ක්‍රියා භාවිතා කරමින් විවිධ යෙදුම් අතර සංකීර්ණ ඒකාබද්ධ කිරීමේ ප්‍රොටෝකෝල ක්‍රියාත්මක කිරීමට ක්‍රියාවලි ප්‍රවේශයක් භාවිතා කිරීමේ හැකියාව ද අපි දුටුවෙමු. ස්ථීර රාජ්‍යයක් පැවතීම මේ සඳහා තීරණාත්මක කාර්යභාරයක් ඉටු කරයි.

ඉහත කරුණු මත පදනම්ව, අපට නිගමනය කළ හැකිය: BPM ශෛලියේ ක්‍රියාවලි ප්‍රවේශය අපට වඩා සංකීර්ණ ව්‍යාපාරික ක්‍රියාවලීන් ස්වයංක්‍රීය කිරීම සඳහා පුළුල් පරාසයක කාර්යයන් විසඳීමට ඉඩ සලසයි, මෙම ක්‍රියාවලීන්ට ඒකාබද්ධ කිරීමේ ක්‍රියාකාරකම් සමගාමීව ගැලපෙන අතර ක්‍රියාත්මක වූ ක්‍රියාවලිය සුදුසු අංකනයකින් දෘශ්‍යමය වශයෙන් ප්‍රදර්ශනය කිරීමේ හැකියාව රඳවා ගනී.

ඒකාබද්ධ කිරීමේ රටාවක් ලෙස සමමුහුර්ත ඇමතුම්වල අවාසි

සමමුහුර්ත අනුකලනය යනු සරලම අවහිර කිරීමේ ඇමතුමයි. එක් උප පද්ධතියක් සේවාදායකයේ පැත්ත ලෙස ක්‍රියා කරන අතර අපේක්ෂිත ක්‍රමය සමඟ API නිරාවරණය කරයි. තවත් උප පද්ධතියක් සේවාදායක පාර්ශවයක් ලෙස ක්‍රියා කරන අතර, නියම වේලාවට, ප්‍රතිඵලයක් අපේක්ෂාවෙන් ඇමතුමක් ලබා දෙයි. පද්ධතියේ ගෘහ නිර්මාණ ශිල්පය මත පදනම්ව, සේවාලාභියා සහ සේවාදායක පැති එකම යෙදුමේ සහ ක්‍රියාවලියක හෝ විවිධ ඒවා තුළ සත්කාරකත්වය දැක්විය හැක. දෙවන අවස්ථාවේදී, ඔබ RPC හි යම් ක්‍රියාත්මක කිරීමක් යෙදිය යුතු අතර පරාමිතිවල මාෂල් කිරීම සහ ඇමතුමේ ප්‍රති result ලය ලබා දිය යුතුය.

BPM ශෛලිය ඒකාබද්ධ කිරීම

එවැනි ඒකාබද්ධ කිරීමේ රටාවකට තරමක් විශාල අඩුපාඩු තිබේ, නමුත් එහි සරල බව නිසා එය ප්‍රායෝගිකව ඉතා පුළුල් ලෙස භාවිතා වේ. ක්‍රියාවට නැංවීමේ වේගය ඔබව ආකර්ෂණය කර ගන්නා අතර "දැවෙන" කාල සීමාවන් තුළ එය නැවත නැවතත් යෙදීමට සලස්වයි, විසඳුම තාක්ෂණික ණයට ලියයි. නමුත් අද්දැකීම් අඩු සංවර්ධකයින් එය නොදැනුවත්වම භාවිතා කරයි, ඍණාත්මක ප්රතිවිපාක අවබෝධ කර නොගනී.

උප පද්ධතිවල සම්බන්ධතාවයේ වඩාත් පැහැදිලිවම වැඩිවීමට අමතරව, "පැතිරීම" සහ "දිගු කිරීම" ගනුදෙනු සමඟ අඩු පැහැදිලි ගැටළු තිබේ. ඇත්ත වශයෙන්ම, ව්‍යාපාර තර්කනය කිසියම් වෙනසක් සිදු කරන්නේ නම්, ගනුදෙනු අත්‍යවශ්‍ය වන අතර, ගනුදෙනු, මෙම වෙනස්කම් මගින් බලපාන ඇතැම් යෙදුම් සම්පත් අගුළු දමයි. එනම්, එක් උප පද්ධතියක් තවත් ප්රතිචාරයක් බලා සිටින තුරු, එය ගනුදෙනුව සම්පූර්ණ කර අගුලු මුදා හැරීමට නොහැකි වනු ඇත. මෙය විවිධ බලපෑම් වල අවදානම සැලකිය යුතු ලෙස වැඩි කරයි:

  • පද්ධති ප්‍රතිචාරය නැති වී ඇත, පරිශීලකයින් ඉල්ලීම් සඳහා පිළිතුරු සඳහා දිගු වේලාවක් බලා සිටී;
  • පිරී ඉතිරී යන නූල් සංචිතයක් හේතුවෙන් සේවාදායකය සාමාන්‍යයෙන් පරිශීලක ඉල්ලීම්වලට ප්‍රතිචාර දැක්වීම නවත්වයි: බොහෝ නූල් ගණුදෙණුව විසින් අත්පත් කරගෙන ඇති සම්පතේ අගුල මත "නැගී" ඇත;
  • අවහිරතා පෙනෙන්නට පටන් ගනී: ඒවා සිදුවීමේ සම්භාවිතාව දැඩි ලෙස රඳා පවතින්නේ ගනුදෙනු වල කාලසීමාව, ව්‍යාපාරික තර්කයේ ප්‍රමාණය සහ ගනුදෙනුවට සම්බන්ධ අගුලු;
  • ගනුදෙනු කල් ඉකුත් වීමේ දෝෂ දිස්වේ;
  • කාර්යයට විශාල දත්ත ප්‍රමාණයක් සැකසීමට සහ වෙනස් කිරීමට අවශ්‍ය නම් සේවාදායකය OutOfMemory මතට වැටේ, සහ සමමුහුර්ත ඒකාබද්ධ කිරීම් තිබීම නිසා සැකසීම “සැහැල්ලු” ගනුදෙනු වලට බෙදීම ඉතා අපහසු වේ.

වාස්තු විද්‍යාත්මක දෘෂ්ටි කෝණයකින්, ඒකාබද්ධ කිරීමේදී ඇමතුම් අවහිර කිරීම තනි උප පද්ධතිවල තත්ත්ව පාලනය නැති වීමට හේතු වේ: එක් උප පද්ධතියක ගුණාත්මක ඉලක්ක වෙනත් උප පද්ධතියක ගුණාත්මක ඉලක්ක වලින් හුදකලා වීම සහතික කළ නොහැක. විවිධ කණ්ඩායම් විසින් උප පද්ධති සංවර්ධනය කරන්නේ නම්, මෙය විශාල ගැටලුවකි.

අනුකලනය කරනු ලබන උප පද්ධති විවිධ යෙදුම්වල තිබේ නම් සහ දෙපැත්තෙන්ම සමමුහුර්ත වෙනස්කම් සිදු කිරීමට අවශ්‍ය නම් දේවල් වඩාත් සිත්ගන්නා සුළු වේ. මෙම වෙනස්කම් ගනුදෙනුවක් බවට පත් කරන්නේ කෙසේද?

වෙනම ගනුදෙනු වලදී වෙනස්කම් සිදු කරන්නේ නම්, ශක්තිමත් ව්‍යතිරේක හැසිරවීම සහ වන්දි ලබා දීම අවශ්‍ය වන අතර, මෙය සමමුහුර්ත ඒකාබද්ධතාවයේ ප්‍රධාන වාසිය සම්පූර්ණයෙන්ම ඉවත් කරයි - සරල බව.

බෙදා හරින ලද ගනුදෙනු ද මතකයට නැඟේ, නමුත් අපි ඒවා අපගේ විසඳුම්වල භාවිතා නොකරමු: විශ්වසනීයත්වය සහතික කිරීම දුෂ්කර ය.

ගනුදෙනු ගැටලුවට විසඳුමක් ලෙස "සාගා"

ක්ෂුද්‍ර සේවාවල ජනප්‍රියතාවය වැඩි වීමත් සමඟ වැඩි ඉල්ලුමක් පවතී සාගා රටාව.

මෙම රටාව දිගු ගනුදෙනු වල ඉහත ගැටළු මනාව විසඳන අතර ව්‍යාපාර තර්කනයේ පැත්තෙන් පද්ධතියේ තත්වය කළමනාකරණය කිරීමේ හැකියාව පුළුල් කරයි: අසාර්ථක ගනුදෙනුවකින් පසු වන්දි ගෙවීම පද්ධතිය එහි මුල් තත්වයට පෙරළා නොගත හැකි නමුත් විකල්පයක් සපයයි. දත්ත සැකසුම් මාර්ගය. ඔබ ක්‍රියාවලිය “හොඳ” අවසානයකට ගෙන ඒමට උත්සාහ කරන විට සාර්ථකව සම්පූර්ණ කරන ලද දත්ත සැකසුම් පියවර නැවත නොකිරීමට ද එය ඔබට ඉඩ සලසයි.

සිත්ගන්නා කරුණ නම්, මොනොලිතික් පද්ධතිවල, ලිහිල්ව සම්බන්ධිත උප පද්ධති ඒකාබද්ධ කිරීමේදී මෙම රටාව අදාළ වන අතර දිගු ගනුදෙනු සහ ඊට අනුරූප සම්පත් අගුලු දැමීම නිසා ඇති වන negative ණාත්මක බලපෑම් ඇති වේ.

BPM ශෛලියේ අපගේ ව්‍යාපාරික ක්‍රියාවලීන් සම්බන්ධයෙන්, Sagas ක්‍රියාත්මක කිරීම ඉතා පහසු බව පෙනේ: Sagas හි තනි පියවරයන් ව්‍යාපාර ක්‍රියාවලිය තුළ ක්‍රියාකාරකම් ලෙස සැකසිය හැකි අතර, ව්‍යාපාර ක්‍රියාවලියේ අඛණ්ඩ තත්ත්වය තීරණය කරයි. වෙනත් දේවල්, Sagas අභ්යන්තර තත්ත්වය. එනම්, අපට අතිරේක සම්බන්ධීකරණ යාන්ත්රණයක් අවශ්ය නොවේ. ඔබට අවශ්‍ය වන්නේ ප්‍රවාහනයක් ලෙස "අවම වශයෙන් එක් වරක්" සහතික සඳහා සහාය ඇති පණිවිඩ තැරැව්කරුවෙකු පමණි.

නමුත් එවැනි විසඳුමකට තමන්ගේම "මිල" ද ඇත:

  • ව්‍යාපාර තර්කනය වඩාත් සංකීර්ණ වේ: ඔබට වන්දි ගෙවීමට අවශ්‍ය වේ;
  • මොනොලිතික් පද්ධති සඳහා විශේෂයෙන් සංවේදී විය හැකි සම්පූර්ණ අනුකූලතාව අත්හැරීමට අවශ්ය වනු ඇත;
  • ගෘහ නිර්මාණ ශිල්පය ටිකක් සංකීර්ණ වේ, පණිවිඩ තැරැව්කරුවකු සඳහා අමතර අවශ්යතාවයක් ඇත;
  • අතිරේක අධීක්ෂණ සහ පරිපාලන මෙවලම් අවශ්‍ය වනු ඇත (සාමාන්‍යයෙන් මෙය ඊටත් වඩා හොඳ වුවද: පද්ධති සේවාවේ ගුණාත්මකභාවය වැඩි වනු ඇත).

මොනොලිතික් පද්ධති සඳහා, "Sags" භාවිතා කිරීම සඳහා සාධාරණීකරණය එතරම් පැහැදිලි නැත. ක්ෂුද්‍ර සේවා සහ අනෙකුත් 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 හි වෙනත් ක්‍රීඩකයෙකුගේ ව්‍යාපාර ක්‍රියාවලිය ඇතුළත් වේ:

පන්තියේ 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}")
}

රූප සටහන:

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

එසේ නොමැති නම්, ක්රීඩකයාගේ හැසිරීම පෙර පැවති හැසිරීමට වඩා වෙනස් නොවේ, එබැවින් රූප සටහන වෙනස් නොවේ.

දැන් අපට ඒ සියල්ල ක්‍රියාත්මක කිරීමට පරීක්ෂණයක් අවශ්‍යයි. බොයිලර් ප්ලේට් එකකින් ලිපිය අවුල් නොකිරීමට මම පරීක්ෂණයේ කේතය පමණක් දෙන්නෙමි (ඇත්ත වශයෙන්ම, මම වෙනත් ව්‍යාපාරික ක්‍රියාවලීන් ඒකාබද්ධ කිරීම පරීක්ෂා කිරීම සඳහා කලින් නිර්මාණය කරන ලද පරීක්ෂණ පරිසරය භාවිතා කළෙමි):

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

පරීක්ෂණය ධාවනය කරන්න, ලොගය බලන්න:

කොන්සෝල ප්රතිදානය

Взята блокировка ключа 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 පැත්තේ අශුභවාදී අගුල් භාවිතා කරමින්, අපි අවශ්ය සියලු අවශ්යතා සපුරාලයි අම්ලය, සහ ධාවනය වන අවස්ථා ගණන වැඩි කිරීමෙන් ව්‍යාපාරික තර්කනය සමඟ යෙදුම පරිමාණය කිරීමේ හැකියාව ද රඳවා ගනී.

කෙසේ වෙතත්, අශුභවාදී අගුලු අපට අවහිර කිරීම් වලින් තර්ජනය කරයි, එයින් අදහස් වන්නේ ව්‍යාපාරික තර්කනයේ සමහර අපකීර්තිමත් අවස්ථාවන් මත අවහිර වූ විට යාවත්කාලීන කිරීම සඳහා තෝරා ගැනීම තවමත් සාධාරණ කාල සීමාවකට සීමා විය යුතු බවයි.

තවත් ගැටළුවක් වන්නේ ව්යාපාර ක්රියාවලියේ ආරම්භය සමමුහුර්ත කිරීමයි. ව්‍යාපාර ක්‍රියාවලි නිදසුනක් නොමැති අතර, දත්ත සමුදායේ ද තත්වයක් නොමැත, එබැවින් විස්තර කරන ලද ක්‍රමය ක්‍රියා නොකරනු ඇත. ඔබට යම් විෂය පථයක් තුළ ව්‍යාපාර ක්‍රියාවලි අවස්ථාවක සුවිශේෂත්වය සහතික කිරීමට අවශ්‍ය නම්, ඔබට ක්‍රියාවලි පන්තිය සහ ඊට අනුරූප විෂය පථය හා සම්බන්ධ යම් ආකාරයක සමමුහුර්ත කිරීමේ වස්තුවක් අවශ්‍ය වේ. මෙම ගැටළුව විසඳීම සඳහා, අපි බාහිර සේවාවක් හරහා URI ආකෘතියේ යතුරක් මඟින් නිශ්චිතව දක්වා ඇති අත්තනෝමතික සම්පතක් මත අගුලක් ගැනීමට ඉඩ සලසන වෙනත් අගුලු දැමීමේ යාන්ත්‍රණයක් භාවිතා කරමු.

අපගේ උදාහරණවල, InitialPlayer ව්‍යාපාර ක්‍රියාවලියේ ප්‍රකාශයක් අඩංගු වේ

uniqueConstraint = UniqueConstraints.singleton

එබැවින්, අදාළ යතුරේ අගුල ගැනීම සහ මුදා හැරීම පිළිබඳ පණිවිඩ ලොගයේ අඩංගු වේ. වෙනත් ව්‍යාපාරික ක්‍රියාවලීන් සඳහා එවැනි පණිවිඩ නොමැත: අනන්‍ය සීමාව සකසා නොමැත.

ස්ථීර තත්ත්වය සමඟ ව්යාපාර ක්රියාවලිය ගැටළු

සමහර විට ස්ථීර තත්වයක් තිබීම උපකාරී වනවා පමණක් නොව, ඇත්ත වශයෙන්ම සංවර්ධනයට බාධා කරයි.
ඔබට ව්‍යාපාර තර්කනය සහ/හෝ ව්‍යාපාර ක්‍රියාවලි ආකෘතියට වෙනස්කම් කිරීමට අවශ්‍ය වූ විට ගැටලු ආරම්භ වේ. එවැනි කිසිදු වෙනසක් ව්‍යාපාර ක්‍රියාවලිවල පැරණි තත්ත්වයට ගැළපෙන බවක් නොපෙනේ. දත්ත සමුදායේ බොහෝ "සජීවී" අවස්ථා තිබේ නම්, නොගැලපෙන වෙනස්කම් සිදු කිරීම jBPM භාවිතා කරන විට අපට බොහෝ විට මුහුණ දීමට සිදු වන ගැටළු රාශියක් ඇති කළ හැකිය.

වෙනස් වීමේ ගැඹුර අනුව, ඔබට ආකාර දෙකකින් ක්රියා කළ හැකිය:

  1. පැරණි එකට නොගැලපෙන වෙනස්කම් නොකිරීමට නව ව්‍යාපාර ක්‍රියාවලි වර්ගයක් සාදන්න, නව අවස්ථා ආරම්භ කිරීමේදී පැරණි එක වෙනුවට එය භාවිතා කරන්න. පැරණි අවස්ථා දිගටම "පැරණි ආකාරයෙන්" ක්‍රියා කරයි;
  2. ව්‍යාපාර තර්කනය යාවත්කාලීන කිරීමේදී ව්‍යාපාර ක්‍රියාවලීන්හි ස්ථීර තත්ත්වය සංක්‍රමණය කරන්න.

පළමු මාර්ගය සරල ය, නමුත් එහි සීමාවන් සහ අවාසි ඇත, උදාහරණයක් ලෙස:

  • බොහෝ ව්‍යාපාර ක්‍රියාවලි ආකෘතිවල ව්‍යාපාර තර්කනය අනුපිටපත් කිරීම, ව්‍යාපාර තර්කනයේ පරිමාව වැඩි වීම;
  • බොහෝ විට නව ව්යාපාර තර්කනයකට ක්ෂණික සංක්රමණයක් අවශ්ය වේ (සෑම විටම පාහේ ඒකාබද්ධ කිරීමේ කාර්යයන් අනුව);
  • යල් පැන ගිය ආකෘති මකා දැමිය හැක්කේ කුමන අවස්ථාවේදීද යන්න සංවර්ධකයා නොදනී.

ප්‍රායෝගිකව, අපි ප්‍රවේශයන් දෙකම භාවිතා කරමු, නමුත් අපගේ ජීවිත සරල කිරීමට තීරණ ගණනාවක් ගෙන ඇත:

  • දත්ත සමුදාය තුළ, ව්‍යාපාර ක්‍රියාවලියේ ස්ථීර තත්ත්වය පහසුවෙන් කියවිය හැකි සහ පහසුවෙන් සැකසූ ආකාරයක් තුළ ගබඩා කර ඇත: JSON ආකෘති තන්තුවකින්. යෙදුම තුළ සහ පිටත සංක්‍රමණයන් සිදු කිරීමට මෙය ඔබට ඉඩ සලසයි. ආන්තික අවස්ථාවන්හිදී, ඔබට එය හසුරුවලින් ද වෙනස් කළ හැකිය (නිදොස්කරණයේදී සංවර්ධනය කිරීමේදී විශේෂයෙන් ප්රයෝජනවත් වේ);
  • ඒකාබද්ධ කිරීමේ ව්‍යාපාර තර්කනය ව්‍යාපාර ක්‍රියාවලීන්ගේ නම් භාවිතා නොකරයි, එබැවින් ඕනෑම වේලාවක සහභාගී වන ක්‍රියාවලීන්ගෙන් එකක් ක්‍රියාත්මක කිරීම නව නමකින් ප්‍රතිස්ථාපනය කළ හැකිය (උදාහරණයක් ලෙස, "InitialPlayerV2"). බන්ධනය සිදු වන්නේ පණිවිඩ සහ සංඥා වල නම් මගිනි;
  • ක්‍රියාවලි ආකෘතියට අනුවාද අංකයක් ඇත, අපි මෙම ආකෘතියට නොගැලපෙන වෙනස්කම් සිදු කළහොත් එය වැඩි කරන්නෙමු, සහ මෙම අංකය ක්‍රියාවලි අවස්ථාවෙහි තත්ත්වය සමඟ ගබඩා කර ඇත;
  • ආකෘතියේ අනුවාද අංකය වෙනස් වී ඇත්නම් සංක්‍රමණ ක්‍රියා පටිපාටිය ක්‍රියා කළ හැකි පහසු වස්තු ආකෘතියකට ප්‍රථමයෙන් ක්‍රියාවලියේ ස්ථීර තත්ත්වය පාදමේ සිට කියවනු ලැබේ;
  • සංක්‍රමණ ක්‍රියා පටිපාටිය ව්‍යාපාරික තර්කය අසල තබා ඇති අතර දත්ත සමුදායෙන් ප්‍රතිසාධනය කරන අවස්ථාවේ ව්‍යාපාර ක්‍රියාවලියේ එක් එක් අවස්ථාව සඳහා "කම්මැලි" ලෙස හැඳින්වේ;
  • ඔබට සියලුම ක්‍රියාවලි අවස්ථා වල තත්වය ඉක්මනින් සහ සමමුහුර්තව සංක්‍රමණය කිරීමට අවශ්‍ය නම්, වඩාත් සම්භාව්‍ය දත්ත සමුදා සංක්‍රමණ විසඳුම් භාවිතා වේ, නමුත් ඔබට එහි JSON සමඟ වැඩ කිරීමට සිදුවේ.

ව්‍යාපාර ක්‍රියාවලි සඳහා මට වෙනත් රාමුවක් අවශ්‍යද?

ලිපියේ විස්තර කර ඇති විසඳුම් අපගේ ජීවිත සැලකිය යුතු ලෙස සරල කිරීමටත්, යෙදුම් සංවර්ධන මට්ටමින් විසඳන ලද ගැටළු පරාසය පුළුල් කිරීමටත්, ව්‍යාපාර තර්කනය ක්ෂුද්‍ර සේවා ලෙස වෙන් කිරීමේ අදහස වඩාත් ආකර්ශනීය කිරීමටත් අපට ඉඩ සලසයි. මේ සඳහා, බොහෝ වැඩ කටයුතු සිදු කර ඇත, ව්‍යාපාරික ක්‍රියාවලීන් සඳහා ඉතා “සැහැල්ලු” රාමුවක් නිර්මාණය කර ඇති අතර පුළුල් පරාසයක ව්‍යවහාරික කාර්යයන්හි සන්දර්භය තුළ හඳුනාගත් ගැටළු විසඳීම සඳහා සේවා සංරචක ද නිර්මාණය කර ඇත. මෙම ප්‍රතිඵල බෙදා ගැනීමට, පොදු සංරචක සංවර්ධනය නිදහස් බලපත්‍රයක් යටතේ විවෘත ප්‍රවේශයට ගෙන ඒමට අපට ආශාවක් ඇත. මෙය යම් උත්සාහයක් හා කාලයක් අවශ්ය වනු ඇත. එවැනි විසඳුම් සඳහා ඇති ඉල්ලුම තේරුම් ගැනීම අපට අමතර දිරිගැන්වීමක් විය හැකිය. යෝජිත ලිපියේ, රාමුවේ හැකියාවන් කෙරෙහි ඉතා සුළු අවධානයක් යොමු කර ඇත, නමුත් ඒවායින් සමහරක් ඉදිරිපත් කර ඇති උදාහරණ වලින් දැකිය හැකිය. කෙසේ වෙතත් අපි අපගේ රාමුව ප්‍රකාශයට පත් කරන්නේ නම්, වෙනම ලිපියක් ඒ සඳහා කැප කරනු ලැබේ. මේ අතරතුර, ඔබ ප්‍රශ්නයට පිළිතුරු දීමෙන් කුඩා ප්‍රතිපෝෂණයක් තබන්නේ නම් අපි කෘතඥ වන්නෙමු:

සමීක්ෂණයට සහභාගී විය හැක්කේ ලියාපදිංචි පරිශීලකයින්ට පමණි. පුරන්නකරුණාකර.

ව්‍යාපාර ක්‍රියාවලි සඳහා මට වෙනත් රාමුවක් අවශ්‍යද?

  • 18,8%ඔව් මම මේ වගේ දෙයක් ගොඩක් කල් ඉඳන් හොයනවා.

  • 12,5%ඔබගේ ක්‍රියාත්මක කිරීම ගැන වැඩි විස්තර දැනගැනීම සිත්ගන්නා කරුණකි, එය ප්‍රයෝජනවත් විය හැක2

  • 6,2%අපි දැනට පවතින රාමු වලින් එකක් භාවිතා කරමු, නමුත් අපි එය ප්‍රතිස්ථාපනය කිරීම ගැන සිතමු1

  • 18,8%අපි දැනට පවතින රාමු වලින් එකක් භාවිතා කරමු, සෑම දෙයක්ම ගැලපේ

  • 18,8%රාමුවකින් තොරව මුහුණ දීම3

  • 25,0%ඔබේම ලියන්න4

පරිශීලකයින් 16 දෙනෙක් ඡන්දය දුන්හ. පරිශීලකයින් 7 දෙනෙක් ඡන්දය දීමෙන් වැළකී සිටියහ.

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න