Kedves Kollégák!
Adódott egy olyan feladat, amikor konkurens batch taszkokkal kéne egy adattáblát feldolgozni. Az lenne a kérdésem, hogy - tapasztalatotok szerint - mit történik akkor, ha a range feltétel szerint egy adott rekord mind a kettő batch taszk adatnézetébe bekerül, de az egyik előbb dolgozza fel azt (fizikai tranzakció, lockolással egybekötött tranzakció indítás, azonnali lockolás, recover hibakezelési mód), és a feldolgozás során kitölt egy olyan adatmezőt, ami miatt az adott rekordot a másik taszknak már át kéne lépnie?
Például mindkét taszk arra szűr, hogy csak a meg nem jelölt rekordokon fusson végig. Az egyik elkap egy rekordot, lockolja, a másik odaér és vár. (Tényleg vár?) Az egyik megjelöli a rekordot, aztán elengedi azt és lép a következőre.
Mi történik ez után? A másik taszk - érzékelve, hogy a rekord
legújabb állapota szerint már nem tartozik az adatnézetbe - átlépi
azt? Vagy - mivel eredetileg belekerült a SELECT eredményhalmazába
- mindenképpen fel akarja dolgozni azt?
Válaszotokat előre is köszönöm!
Üdvözlettel:
Dávid
Szia Péter!
Köszi a választ! Ez a megoldás vélhetően jó, amit írsz. Én most egyelőre azt csináltam, hogy a batch program rekord suffixét egy feltétel blokkba teszem, hogy csak akkor fusson le, ha a flag mező még nincs beállítva. Az érdekelne nagyon, hogy vajon erre szükség van-e? (Félek tőle, hogy igen.) Egyébként SQL Server 2016 Express-ről van szó.
Üdvözlettel:
Dávid
Szia Dávid,
Én is a Péter által említett megoldást javasolnám, mi is ezt használjuk hasonló esetekben.
A mi esetünkben van még egy oka ennek, mégpedig az, hogy mi Oracle adatbázis kezelőt használunk, és az szeret „fetch out of sequence” hibaüzenetet dobni (uniPaaS és xpa 3.x is), ha olyan Magic batch taszkot írunk, ami több rekordra szűr pl. egy feldolgozva flag-re, és a rekord utóban módosítja is azt, illetve hasonló a helyzet rekord szintű tranzakció esetén is. Szóval nálunk a „sima tartományozás” módszer semmiképpen sem jöhetne szóba ilyen esetben. Hogy SQL szervernél van-e hasonló probléma, azt nem tudom.
Még egy dolog, azt írod:
„Én most egyelőre azt csináltam, hogy a batch program rekord suffixét egy feltétel blokkba teszem, hogy csak akkor fusson le, ha a flag mező még nincs beállítva.”Ez szerintem még mindig nem lenne neked elég, mert ilyenkor a Magic a kifejezés kiértékeléséhez nem kéri el az adatbáziskezelőtől újra az adott mező értékét. Ezt a gateway log bekapcsolásával ellenőrizheted, törésponttal állítsd meg az adott block előtt a feldolgozást, és ha átlépsz az adott utasításon, akkor nem fog a Magic fetch utasítást írni a gateway logba. Úgyhogy itt csak egy call subtask menthetné meg a helyzetet, amiben Link utasítással ismét ráolvasol a kérdéses rekordra, Cache=No-val. Ezzel együtt szerintem az első megoldással sok későbbi problémától kíméled meg magadat.
Üdvözlettel:
Bakos Gyula
SZEGED Software Zrt.
--
Azért kapta ezt az üzenetet, mert feliratkozott a Google Csoportok „Magic Support Levelezőlista” csoportjára.
Az erről a csoportról és az ahhoz kapcsolódó e-mailekről való leiratkozáshoz küldjön egy e-amailt a(z) magic-suppor...@googlegroups.com címre.
Ha üzenetet szeretne küldeni ebbe a csoportba, küldjön e-mailt a(z) magic-...@googlegroups.com címre.
A csoportot a(z) https://groups.google.com/group/magic-support címen keresheti fel.
További lehetőségekért látogasson el ide: https://groups.google.com/d/optout.
Kedves Gyula! Kedves Péter! Kedves Kollégák!
Bár az idő eléggé szorít, mégsem maradt már hátra, mint kipróbálni, amire Gyula és Péter is biztatott. Ennek eredményét szeretném megosztani Veletek.
Először is magáról a feladatról néhány szót: bizonyos
felhasználói interakciók hatására párhuzamos batch taszkok
indulnak, akik fel akarják dolgozni egy tábla kevés számú, még fel
nem dolgozott (néhány 10 db) rekordját. Egy munkaállomáson csak
1-1 ilyen taszk fut, de a több munkaállomás miatt előfordulhatnak
párhuzamos feldolgozások. A cél, hogy megakadályozzuk,
hogy egy rekordra véletlenül kétszer fusson le egy ilyen
feldolgozás.
A feladat teszteléséhez felvettem egy táblát, amelynek 2 mezője volt: egy auto növekvő kód és egy numerikus flag. A táblán 1 db 2 szegmenses index volt: flag ASC, kód ASC. 10 rekordot vettem föl a táblába.
Ezek után készítettem 2 batch taszkot. Mindkettő ugyanazon a
táblán futott végig, azokra a rekordokra range-elve, ahol a flag
0. "A" taszk felülről lefelé futott végig a rekordokon és a
flag-et 1-re állította, "B" taszk alulról felfelé futott végig a
rekordokon és a flag-et 2-re állította. Mindkét taszk 2 mp-et várt
minden rekord utóban. Fizikai tranzakciót használtam, lockolással
együtt indított tranzakcióval, azonnali lockolással és recover
hibakezelési stratégiával. "B" párhuzamos taszkot "A"
indította a taszk prefixében.
Azt tapasztaltam, hogy az első 5 rekordban 1 lett a flag értéke, a második 5-ben pedig 2, miközben "A" és "B" taszk is a feldolgozás második felében 5-5 db "record has been changed by another user" hibát dobott. Ugyanez volt az eredmény akkor is, ha a rekord utóban update előtt ellenőriztem a flag értékét. Vagyis a range által visszaadott rekordokon - eredeti adattartalommal - mindenképpen végig ment mind a kettő, emellett viszont azt azért észre vették, ha valaki azt a rekordot már módosította, és az ilyen rekordokat eldobták. Ha mindehhez egy üres "Record changed by another user" hiba esemény figyelőt is felvettem mindkét taszkba, ignore hibakezelési stratégiával, akkor - azonos eredmény mellett - a hibaüzeneteket is megúsztam.
Szóval ezek szerint nem muszáj (nekem) egyesével foglalnom a kordokat, de a flag értékét teljesen fölösleges vizsgálnom, és fel kell vennem egy hibakezelőt, hogy ne legyen futási hiba. Egyet értetek ezzel?
Előre is köszi a válaszokat!
Üdvözlettel:
Dávid
Szia,
Természetesen egy program akkor „jó”, ha a megfelelő teszteken sikeresen átesett, így jó lehet a te megoldásod is, ha a tesztek után megfelelőnek ítéled.
A következőket azonban hozzátenném:
Üdv: Gyula
--
--
Azért kapta ezt az üzenetet, mert feliratkozott a Google Csoportok „Magic Support Levelezőlista” csoportjára.
Az erről a csoportról és az ahhoz kapcsolódó e-mailekről való leiratkozáshoz küldjön egy e-amailt a(z) magic-support+unsubscribe@googlegroups.com címre.
Szia Gyula!
Köszi a válaszodat! Ha a két taszkot azonos sorrendben szalajtom végig a rekordokon (az elején ilyen volt a teszt, mert elszúrtam az indexet :) ), akkor minden rekordba 1-es kerül a végén, a "B" taszk meg kb. 7 hibát dob. (Nyilván az indítási késleltetés miatt.)
Teljesen egyetértek a kódszervezési megjegyzéseiddel! Ha lesz időm, majd átírom az enyéimet is. A probléma tulajdonképpen marginális, ritkán és kevés adattal fordulhat csak ilyen elő, desktop környezetben, csak a hiba lehetőségét kell kizárni. (Értem, hogy pont attól válik az egész bizonytalanná, hogy a Magic kezeli le a hibát. :) Igyekszem majd algoritmikusan védekezni.)
Üdv:
Dávid
Szia Péter!
Köszi a válaszodat! Ahogy Gyulának írt válaszomban is írtam: alkalom adtán igyekszem átszervezni majd a kódot.
A helyzet az, hogy november 1-étől minden háziorvosnak csatlakoznia kell az eEgészségügyi felhőhöz, ami azt jelenti, hogy bizonyos dolgok megtörténtéről jelentést kell küldeni valós időben. Ha ez valami miatt meghiúsul (nincs internet, nincs ott jogosult személy, nem elérhető a felhő, stb.), akkor ezeket az eseményeket naplózni kell és alkalom adtán újra be kell küldeni őket.
A kommunikáció gerincét egy szerveren futó PHP wrapper kódom
viszi, nekem "csak" azzal kéne kommunikálnom, de úgy látom, hogy a
Magic-et nem arra a feladatra tervezték, hogy képernyő nélküli,
aszinkron batch taszkokból nagy hibatűrésű, szükség esetén
"hibajavító" módon működő back end rendszert írjanak benne.
Úgyhogy most a lehetőségek a szükségek és a határidő szorításában
vergődve született ez a megoldás, ami - mint kiderült - működik,
de lehet, hogy nem a legjobb. Ha még élek november 1-e után, akkor
átírom a kódot. :)
Üdv és köszönet:
Dávid
Marci azt mondaná, tipikus xpi-s feladat… 😊
Gyula
From: magic-...@googlegroups.com [mailto:magic-...@googlegroups.com] On Behalf Of Tisch Dávid
Sent: Tuesday, September 26, 2017 5:27 PM
To: magic-...@googlegroups.com
Subject: Re: [Magic Support] Re: Konkurens batch taszk kérdés
Szia Péter!
--
Azért kapta ezt az üzenetet, mert feliratkozott a Google Csoportok „Magic Support Levelezőlista” csoportjára.
Az erről a csoportról és az ahhoz kapcsolódó e-mailekről való leiratkozáshoz küldjön egy e-amailt a(z) magic-suppor...@googlegroups.com címre.
:D És ha nem, akkor is. ;)
--
Azért kapta ezt az üzenetet, mert feliratkozott a Google Csoportok „Magic Support Levelezőlista” csoportjára.
Az erről a csoportról és az ahhoz kapcsolódó e-mailekről való leiratkozáshoz küldjön egy e-amailt a(z) magic-support+unsubscribe@googlegroups.com címre.
Szia Ámor!
Köszi a választ! Sejtettem, hogy van a kollektív tudatban sok minden a témával kapcsolatban. :)
Az Általad mondottakhoz én annyit tennék hozzá, hogy mi az SQL
Server-es átállás kapcsán majdnem elveszítettük a teszt
felhasználónkat, pedig a teszt időszak alatt ingyen használta a
programot, annyi problémánk volt az Általad is említett kalóz
tranzakció kezeléssel és lockolással. Végül a kritikus helyeken
direkt SQL taszkokkal sikerült felül kerekednünk a problémán,
exkluzív tábla lokkolásokkal, meg mindenféle, de azt a néhány
hetet nem kívánom senkinek. És itt csak 2(!) párhuzamos
felhasználó volt, és a rendszer nem kifejezetten "misson
critical", hogy Marcit idézzem. :)
A fenti, "tuti" megoldás bonyolultsága miatt most, amikor utólag merült fel a konkurencia problémája, nem szerettem volna ebbe az irányba elmozdulni, mert nem volt rá elég időm, arra viszont aztán rájöttem, hogy az általam preferált és Nektek is bemutatott félmegoldás egyáltalán nem is megoldás, mert igaz ugyan, hogy a rekordokat végül csak 1 taszk írja, de csak a rekord utó végén derül ki, hogy baj van, akkor viszont a feldolgozás (adatbeküldés felhőbe, stb.) már visszavonhatatlanul megtörtént.
Megpróbáltam az SQL Server által biztosított lehetőségek közül az
application lock-ot használni, ami egy globális adatbázis mutex
objektum (ezzel MySQL alatt nagyon jó tapasztalatom van), de ezt
még direkt SQL taszkkal sem tudtam működésre bírni. Semmi
visszacsatolást nem tudtam ugyanis kiszedni az adatbáziskezelőből,
hogy sikerült-e a dolog vagy sem. (Kimeneti paramétere csak szóló
SELECT utasításnak lehet, a tranzakciós változók (@result) nem
őrzik meg az értéküket a direkt SQL taszkok között, lekérdező
függvény nincs, ráadásul az összes helyi Magic-es taszk egy
felhasználóé SQL oldalon, úgyhogy eleve nem védené meg őket
egymástól...) 3-4 órám elment a kísérletezéssel.
Végül azt a megoldást választottam, hogy létrehoztam egy
[TáblaNév, KontextusID] táblát, és egy programmal ebbe írom föl,
ha valaki batch végrehajtást indít. Ez a taszk a már említett
"Record has been changed..."-del gondoskodik róla, hogy csak 1
írhasson be, utána egy programmal kiolvastatom hogy ki van beírva,
és ha a saját Kontextus ID, akkor szabad a pálya, ha meg nem,
akkor bele se lép a record prefixbe. Munka végén meg kitörli
magát. Vagyis tulajdonképpen implementáltam egy virtuális mutexet,
és még azt is nyertem vele, hogy nem a fizikai táblát kell
lockolnom, így a batch végrehajtás alatt a beírás zavartalanul
mehet tovább.
Ez a megoldás most jónak tűnik, de ha szerintetek van ezzel valami gyakorlati probléma, akkor kritizáljátok meg, legyetek szívesek!
Köszi az eddigieket és az ez utániakat is!
Üdv:
Dávid
U.I.: Ámor! Én még szeretem a Magic-et, ennél a szűk határidős
feladatnál - ahogy már Te is sokszor mesélted - sok fejlesztős
cégeket vertem fejlesztési időben (pedig csak rész munkaidőben
nyomom), de nem véletlenül imádom a PHP-t. Ott ha azt mondom, hogy
BEGIN TRANSACTION, akkor az úgy is van. :) Nincs varázslat, nincs
Magic. ;)