Šodien saskāros ar diezgan interesantu problēmu, kuras risinājumam veltīju apmēram agra rīta 4 stundas :)
Neliels historical background izklāsts par problēmu domēnu.
Veidoju sistēmu, kura izmanto WCF un MQ, lai savā starpā veidotu reliable komunikācijas starp vairākām sistēmas komponentēm, kuras atrodas uz dažādiem serveriem. Kopējais raksts par reliable communication .Net sistēmās vēl top, bet šoreiz diezgan interesants stāsts par vienu no aspektiem ar ko saskāros veidojot šo sistēmu.
Situācija ir sekojoša:
- Viena no sistēmas komponentēm nosūta ziņojumu rindā izmantojot NetMsmqBinding komponenti.
- Otra sistēmas komponente no tās pašas rindas nolasa ziņojumus izmantojot to pašu WCF komponenti.
- Rinda ir transakcionāla, t.i., sūtīšana un nolasīšana rindā notiek transakcijā.
- Ziņojuma nolasīšanas laikā tiek izmantots arī SQL serveris.
- Tiklīdz tiek izmantots kāds cits transakcijas piegādātājs, tā nolasīšanas transakcija automātiski tiek deleģēta DTC komponentei, kas atbild par dažāda rakstura sadalīto transakciju savstarpējo koordinēšanu.
- Ziņojuma nolasīšanas laikā notiek arī sistēmas aktivitātes logging, kas žurnalizē visu, kas notiek tajā momentā.
- Rinda iztransakcionāla un nolasīšanas operācijas failure gadījumā kopējā transakcija tiek rollback’ota.
Pēdējais punkts arī ir interesantākais šajā scenārijā. Common practice ir tāds, ka vairums vienas un tās pašas sistēmas komponentes saņem vienu un to pašu Sql savienojumu darbam ar datubāzi. Par cik žurnalizēšana notiek ar tā paša Sql savienojuma starpniecību, tad problēma rodas apstāklī, kad ziņojuma nolasīšana no rindas nav sekmīga gan MQ, gan SQL transkacijas tiek rollback’otas, tas nozīmē, ka arī logging statementi tiek rollback’oti, kas savukārt rezultējas situācijā, ka pēc nesekmīgas ziņojuma apstrādes Log tabula ir tukša :)
Pēc neilgas (patiesībā diezgan ilgas meklēšanas, jo vairums laika pavadīju meklējot nepareizā virzienā) research, uzgāju SQL Connection String interesantu īpašību – Enlist.
Citāts no dokumentācijas:
“true indicates that the SQL Server connection pooler automatically enlists the connection in the creation thread's current transaction context.”
Lai liktu lietā šo iespēju, diemžēl ir jāveido jauns savienojums ar SQL serveri, kura parametros Enlist īpašība ir norādīta ar vērtību ‘false’ (Enlist=false;).
Un vispār no pieredzes varu teikt, ka parasti logging datu bāzes savienojumu izdalu no kopējā savienojuma klāsta, par cik tas dod iespēju veidot žurnalizēšanu arī citā datu bāzē atvieglojot operacionālās datubāzes noslodzi un izmērus.
Cerams, ka noderēs!