ugrás a tartalomhoz

pub/sub event reflection

inf3rno · 2014. Május. 31. (Szo), 14.15
Nemrég találkoztam egy érdekes problémával, gondoltam megosztom veletek is. Az egész data binding-hoz kapcsolódik, illetve js-hez, de általánosítható bármilyen nyelvre.

Az alap probléma gyakorlatilag egy általános data binding megoldás keresése volt. Elég szépen le lehet írni a data binding-ot, mert körülbelül arról van szó, hogy adat forrásokat kell szinkronba hozni. Az egyik a model, a másik a view, de lehet tetszőleges számú model és view is. Pl backbone esetében hozzácsapnak egy model-t egy view-hoz és szevasz. Ha általánosan akarjuk leírni a dolgot, akkor n:m reláció esetében a legegyszerűbb, ha létrehozunk egy relationship típust, amiben letároljuk, hogy mi áll mivel kapcsolatban. Szóval arra gondoltam, hogy csinálni kell egy Hub osztályt, ami majd továbbítja a többi adatforrásnak a change event-eket.

A gond csak ott van ezzel a megközelítéssel, hogy az adatforrás, ami kiváltja az eseményt szintén fel van iratkozva erre a Hub-ra, mint esemény figyelő. Így könnyen előfordulhat az, hogy elkezd a rendszer oszcillálni attól, hogy az adatforrás és a hub között vagy két adatforrás között oda-vissza verődnek az események. Egy change egy adatforráson kivált egy eseményt, ezt publikálja a Hub-on, ami visszaküldi ugyanazt az eseményt, ami szintén kivált egy change-t, ami kivált egy új eseményt, és így tovább... Mit gondoltok mi erre az általános megoldás?
 
1

Ránézésre ez az egész

inf3rno · 2014. Május. 31. (Szo), 15.04
Ránézésre ez az egész probléma egy az egyben megegyezik azzal, amikor több adatbázist próbálnak szinkronban tartani egymással egy hálózaton keresztül. Ez baromira bonyolult, ezért nem hiszem, hogy nekem általános megoldásra lenne szükségem, sokkal inkább megszorításokra, amivel el lehet érni, hogy automatikusan szinkronban maradjon minden.

Gondoltam arra, hogy egy irányúsítani kellene az események folyását, tehát mondjuk van egy központi model, és minden adatforrás arról frissíti saját magát. Ez a megoldás biztosan nem működik, több okból sem, az egyik, hogy nem lehet bonyolultabb hub hierarchiát építeni, mert mindig a legfelső szinthez kellene hozzányúlni mindennek, a másik az, hogy a view esetében nincs választási lehetőség, mindenképp az input mező változásait kell, hogy figyeljük, és az input mező az egyedüli dolog, amihez hozzáfér a felhasználó, a memóriához közvetlenül nem.
2

Az adatforrás tudja, hogy mi

Ajnasz · 2014. Május. 31. (Szo), 16.09
Az adatforrás tudja, hogy mi az aktuális érték? Ha igen, akkor lehet figyelni, hogy ténylegesen volt-e változás és csak akkor ellőni az eseményt.
3

Ez csak szinkron kódnál oldja

inf3rno · 2014. Május. 31. (Szo), 18.11
Ez csak szinkron kódnál oldja meg a problémát. Egyébként aszinkron kódnál, ha átmeneti állapotban váltasz ki új eseményt, akkor valami ilyesmi lesz a végeredmény: https://www.youtube.com/watch?v=WasYuiOk5xQ. Az alkalmazás elkezd oszcillálni a két végállapot között.
4

Miért nem tageled meg az

BlaZe · 2014. Jún. 10. (K), 20.48
Miért nem tageled meg az eventet az originatorrel? Arra tudsz filterezni. De úgy általánosságban az egy kicsit gyanús, hogy valaki egy saját maga által kiadott eventre figyel. Ez első blikkre inkább architekturális problémának tűnik. Lehet van rá valid use case, vagy csak én nem értem :) Tudsz hozni egy konkrét példát?
5

Nope, saját maga által

inf3rno · 2014. Jún. 10. (K), 22.08
Nope, saját maga által kiadott event-re nyugodtan figyelhet, ez nálam egyáltalán nem gond, találkoztam már pár helyen ilyennel...
6

Tudsz mondani egy példát,

BlaZe · 2014. Jún. 10. (K), 23.28
Tudsz mondani egy példát, hogy el tudjam képzelni? Lehet teljesen mást értek a leírtak alatt, mint amire gondolsz. Első blikkre az, hogy valaki a saját inputjára publikál, nekem egy picit "smelly" :)

Megoldódott már amúgy? Elég csöndes lett ez a téma.
7

https://github.com/szjani/pre

inf3rno · 2014. Jún. 11. (Sze), 00.45
https://github.com/szjani/predaddy-issuetracker-sample/blob/master/src/hu/szjani/domain/issue/Issue.php

Itt van pl egy olyan helyzet, amikor a domain object kivált egy domain event-et a konstruktorban, aztán saját maga kezeli le a created metódusban. DDD-ben ez elég tipikusnak tűnik, bár nem ástam bele magam kimondottan, de láttam már máshol is ugyanezt. Úgy nézem, hogy valószínűleg az indokolja, hogy event sourcing esetében szükség lehet az aggregate újbóli felépítésére a tárolt event-ek alapján.

A hub-os dolog nem sokban különbözik. Ott is ugyanúgy felteszi egy bus-ra az event-eket a data source, amiket ő is figyel, csak annyi a különbség, hogy ott a saját maga által kiváltott event-eket nem ő kezeli le... Hmm ami érdekes, hogy ugyanaz a megoldás működhet, mint amit szjani alkalmazott. Szóval hogy mondjuk egy set() metódus csak egy event-et vált ki, de nem csinál semmit a property-kkel, illetve az event elkapása megváltoztatja a property-ket, de nem vált ki újabb event-et... Ez bizonyos típusú rendszereknél működhet, de sajnos ez sem általános megoldás, mert szűkíti a lehetőségek körét, egy hub-nál nem jutnának tovább az event-ek, hacsak nem több hub-ot kapcsolnánk össze azok továbbítására...

Egyébként megoldódott:

http://stackoverflow.com/questions/23968758/how-to-avoid-event-reflection-by-pub-sub

http://programmers.stackexchange.com/questions/241599/how-to-avoid-oscillation-by-async-event-based-systems

de ha van észrevételed, nyugodtan jelezd.

Én arra gondoltam, hogy a legáltalánosabb megoldás minden kívülről indult eseményhez egy-egy context-et hozzácsatolni, és ezt a context-et végigvinni új események kiváltásakor is. Erre nyilván ki kell alakítani egy context továbbító rendszert. Így ha egy konkrét context id-vel ellátott event valamikor már kezelve volt 1-1 handler által, akkor az nem kerül újra kezelésre. Ezt megvalósítani nem egyszerű, az event-et kiváltó osztályba muszáj beleírni hasonló módon, mint pl a backbone-nál, ahol options-t fogad el egy csomó metódus második paraméterként, amiben át lehet adni egy silent-et, ha meg akarjuk szakítani az oszcillációt... Ez mondjuk egy gyenge manuális kezelése a problémának. Ott az váltja ki az oszcillációt, hogy a view-ot és a model-t szinkronban kell tartani, és ezek kölcsönösen figyelik egymás eseményeit, illetve módosuláskor mindegyik eseményt vált ki, amit a másik elkap...
8

Ok, így már azt hiszem jobban

BlaZe · 2014. Jún. 12. (Cs), 21.54
Ok, így már azt hiszem jobban értem. Általánosságban elég nehéz erről beszélni szerintem. Eleve különböző feladatokra különböző topológiák megfelelőek. Említették pl a queue-t is az egyik válaszban, ami by design biztosítja, hogy csak 1 consumer dolgozza fel az evented. Amit írsz contextet, az meg hasonlít arra, amit az előző válaszomban írtam, hogy meg lehet fejelni az eventet valamivel (header), ami tartalmazza azokat az infókat, ami alapján a subscriber/consumer el tudja dönteni, hogy érdekli-e az event, vagy sem (message id, originator, event type, correlation id stb). Arra már tudsz filtert/szabályrendszert írni. Egy másik opció, hogy lehet különböző eventeket különböző destination-ökre küldeni, nem kell mindennek egy nagy központi buson lógnia.
9

Ez a könnyebbik része, a

inf3rno · 2014. Jún. 12. (Cs), 23.50
Ez a könnyebbik része, a nehezebbik, ha egy event küldésének a kezelése közben egy újabb event keletkezik, aztán annak a kezelése közben egy még újabb, és így tovább... Nehéz olyan általános rendszert tervezni, ami az ilyen jellegű ciklusokat elvágja a megfelelő helyen, viszont ha sikerülne valamilyen egyszerű automatizált megoldással előállni, akkor pl sokkal egyszerűbb lenne data binding-ot csinálni egy MVC rendszerhez. Most jelenleg pl a backbone esetében ha akarsz egy új widget osztályt, akkor manuálisan kell a data binding-ot megoldanod. Nem tudom a többi keretrendszerrel mi a helyzet... Ez nem elsősorban kényelmi szempont, hanem nagyon könnyű hibázni vele, tesztelni meg nem valami egyszerű.
10

egy event küldésének a

Hidvégi Gábor · 2014. Jún. 13. (P), 07.20
egy event küldésének a kezelése közben egy újabb event keletkezik
FIFO?
11

Kifejtenéd?

inf3rno · 2014. Jún. 13. (P), 14.03
Kifejtenéd?
12

Parancssor

Hidvégi Gábor · 2014. Jún. 13. (P), 14.30
A munkámban pont most kellett megvalósítani egy ilyet. A parancsok egy tömbbe kerülnek, a feldolgozó ebből kiveszi az első elemet (array_shift()), és lefuttatja a hozzá tartozó parancsot. Ha a parancs feldolgozása közben új események váltódnak ki, a hozzájuk tartozó parancsok a parancssor elejére kerülnek.

FIFO = First In, First Out.
13

És ez hogy oldja meg az

inf3rno · 2014. Jún. 13. (P), 14.51
És ez hogy oldja meg az említett problémát?
14

a nehezebbik, ha egy event

Hidvégi Gábor · 2014. Jún. 13. (P), 15.28
a nehezebbik, ha egy event küldésének a kezelése közben egy újabb event keletkezik, aztán annak a kezelése közben egy még újabb, és így tovább... Nehéz olyan általános rendszert tervezni, ami az ilyen jellegű ciklusokat elvágja a megfelelő helyen
Ezt oldja meg.
15

Hogyan?

inf3rno · 2014. Jún. 14. (Szo), 14.09
Hogyan?
16

Azt hiszem, elbeszélünk

Hidvégi Gábor · 2014. Jún. 14. (Szo), 14.34
Azt hiszem, elbeszélünk egymás mellett, nem értettem meg a problémát.