Jak řešit notifikace přes websockety

AdamVyborny
Člen | 36
+
0
-

Zdravím všechny. Chci řešit notifikace přes websockety Podařilo se mi rozběhat DemoChat přes iPub/Websockets, takže mám funkční server-side a client-side implementaci socketů do Nette, nicméně důvod proč řeším WS jsou notifikace. Avšak nemám úplně představu jak je řešit. Moje vize je taková, že sockety umějí řešit pouze realtime notifikování a já potřebuji notifikace v aplikaci aby fungovaly na podobném principu jako na Facebooku. To pro mě znamená, že si notifikace budu ukládat do DB, při loginu usera mu je načtu pravděpodobně do objektu, aby se nemusely při každém refreshi načitat znovu a všechny nové notifikace už mu budou chodit přes sockety, s tím, že se budou zase i ukládat do DB, aby byly k dispozici při jeho příštím loginu. Dává tato cesta smysl nebo na to jdu úplně špatně?

srigi
Nette Blogger | 558
+
0
-

Bohuzial budes to musiet spravit trochu zlozitejsie. PHP + webserver je z podstaty request-response model. To znamena, ze ked user requestne stranku, PHP vykona kod a skonci (user ma ale stranku stale zobrazenu). Preto ak userovi ma prist notif. nemas ju ako poslat, pretoze PHP kod uz nezije.

Riesenie je spravit si pre websocket server cli workera pocuvajuceho mesage-queue (MQ consumer). V tomto ma iPub/Websockets trochu nevyhodu, podporuje iba ZMQ, na toto je ale vhodnejsia RabbitMQ.

Editoval srigi (4. 5. 2017 8:46)

AdamVyborny
Člen | 36
+
0
-

srigi napsal(a):

Bohuzial budes to musiet spravit trochu zlozitejsie. PHP + webserver je z podstaty request-response model. To znamena, ze ked user requestne stranku, PHP vykona kod a skonci (user ma ale stranku stale zobrazenu). Preto ak userovi ma prist notif. nemas ju ako poslat, pretoze PHP kod uz nezije.

Riesenie je spravit si pre websocket server cli workera pocuvajuceho mesage-queue (MQ consumer). V tomto ma iPub/Websockets trochu nevyhodu, podporuje iba ZMQ, na toto je ale vhodnejsia RabbitMQ.

Mě je jasný, jak funguje PHP, proto se ptám jestli je ta cesta kterou popisuju správná, tj načíst při loginu proběhlé notifikace do objektu a každou další notifikaci řešit přes websockety až do té doby než se uživatel odhlásí (nebo při refreshi stránky přijdu o ty notifikace od websocketů? Takže si při každým loadu natáhnu notifky z DB, takže asi už né do objektu a realtime budou chodit jen vždy do refreshe?)

Taky si mě trochu rozhodil s RabbitMQ? Co to pro mě znamená? V dokumentaci k iPub/Websockets se právě psalo, že to realtime notifikace řeší. V čem by pro mě bylo lepší použít RabbitMQ než ZeroMQ? A nebo naopak pokud bych zůstal u ZeroMQ o co přijdu nebo v čem to bude složitější?

Děkuji

srigi
Nette Blogger | 558
+
0
-

AdamVyborny napsal(a):

…načíst při loginu proběhlé notifikace do objektu a každou další notifikaci řešit přes websockety až do té doby než se uživatel odhlásí (nebo při refreshi stránky přijdu o ty notifikace od websocketů? Takže si při každým loadu natáhnu notifky z DB, takže asi už né do objektu a realtime budou chodit jen vždy do refreshe?)

Potom ale websockets vobec nepotrebujes, normalne tie notif. do stranky vyrenderuj. Workera potrebujes aby si poslal notif. do vyrenderovanej stranky, ked uz je request skonceny. RMQ je lepsi v tom, ze ma persistenciu na disk a vie nezbehnute ulohy vratit spat do queue, checkuje si ci workeri ziju a ACK ulohy a pod.
ZMQ je v podstate obycajna pipe medzi procesmi, ak worker zdochne, zaslane mesages sa ti stratia.

AdamVyborny
Člen | 36
+
0
-

srigi napsal(a):

AdamVyborny napsal(a):

…načíst při loginu proběhlé notifikace do objektu a každou další notifikaci řešit přes websockety až do té doby než se uživatel odhlásí (nebo při refreshi stránky přijdu o ty notifikace od websocketů? Takže si při každým loadu natáhnu notifky z DB, takže asi už né do objektu a realtime budou chodit jen vždy do refreshe?)

Potom ale websockets vobec nepotrebujes, normalne tie notif. do stranky vyrenderuj. Workera potrebujes aby si poslal notif. do vyrenderovanej stranky, ked uz je request skonceny. RMQ je lepsi v tom, ze ma persistenciu na disk a vie nezbehnute ulohy vratit spat do queue, checkuje si ci workeri ziju a ACK ulohy a pod.
ZMQ je v podstate obycajna pipe medzi procesmi, ak worker zdochne, zaslane mesages sa ti stratia.

No já měl tu představu, že tím eliminuju nějakej AJAX, kterej mi bude co vteřinu posílat dotaz do DB. Potřebuju aby ty notfikace fungovaly realtime mezi refreshema

Editoval AdamVyborny (4. 5. 2017 10:31)

newPOPE
Člen | 648
+
0
-

Vyzera, ze si nerozumiete :)

@AdamVyborny zrejme potrebujes hybrid. Ked loadnem tak tam notif. uvidim. ale ked nebudem klikat chces aby dalsie notif. prichadzali?.

No na taky hybrid by som sa osobne vykaslal a urobil to ako samostatnu vec asi takto:

  1. normalny request a dostanem response stranky
  2. nasledne na to nastartujem na strane klienta ajax klienta ktory bude kontrolovat na serveri notifikacie.
  3. server posle zoznam notif. a len ich vyrenderujes

no a co je na tom tazke, v podstate nic. pouzijes na to snippety a mas po probleme :) akurat si napises aby ti klient (browser) kontroloval po nejakom case (1s, 2s, interval si vyberies) notifikacie na serveri. That's all.

Editoval newPOPE (4. 5. 2017 12:01)

srigi
Nette Blogger | 558
+
0
-

AdamVyborny napsal(a):

No já měl tu představu, že tím eliminuju nějakej AJAX, kterej mi bude co vteřinu posílat dotaz do DB. Potřebuju aby ty notfikace fungovaly realtime mezi refreshema

Prave preto potrebujes nejakeho /keep-alive daemona/ (cli workera), pretoze PHP zivotny cyklus konci s requestom. Cli worker spravi websocker server, na ktory sa stranka po vyrenderovani pripoji. Ked cli worker obdrzi message z MQ, preposle to websocketom do vyrenderovanej stranky. Ina ceste proste nie. PHP+webserver nefunguje ako daemon (Node.js naopak ano, tam sa s tym takto netreba srat).

srigi
Nette Blogger | 558
+
0
-

newPOPE napsal(a):

2. nasledne na to nastartujem na strane klienta ajax klienta ktory bude kontrolovat na serveri notifikacie.
3. server posle zoznam notif. a len ich vyrenderujes

Ja to chapem tak, ze to prave nechce, ze by chcel spravit server-push (cez WS).

AdamVyborny
Člen | 36
+
0
-

newPOPE napsal(a):

Vyzera, ze si nerozumiete :)

@AdamVyborny zrejme potrebujes hybrid. Ked loadnem tak tam notif. uvidim. ale ked nebudem klikat chces aby dalsie notif. prichadzali?.

No na taky hybrid by som sa osobne vykaslal a urobil to ako samostatnu vec asi takto:

  1. normalny request a dostanem response stranky
  2. nasledne na to nastartujem na strane klienta ajax klienta ktory bude kontrolovat na serveri notifikacie.
  3. server posle zoznam notif. a len ich vyrenderujes

no a co je na tom tazke, v podstate nic. pouzijes na to snippety a mas po probleme :) akurat si napises aby ti klient (browser) kontroloval po nejakom case (1s, 2s, interval si vyberies) notifikacie na serveri. That's all.

Takhle řeším ty notifikace teď, chtěl jsem tím eliminovat to, že při 100 aktivních userech mám 100 queries za sekundu do DB

Editoval AdamVyborny (4. 5. 2017 12:55)

newPOPE
Člen | 648
+
0
-

Tak ked tam mas len 100 pre 100 ludi tak to si na tom velmi dobre (moj nazor) vacsinou tych queries tam byva viac. Myslis, ze ked vymenis princip, ze znisis pocet queries? Mozno na DB ale zase potrebujes dalsie sluzby (spominany Rabbit…)

Nechcem nejako odradzovat ale v konecnom dosledku 100queries moze byt vela ale aj malo…

Dalsi princip ktory mozes pouzit je:

  1. render stranky
  2. klient (JS) sa pripoji na socket
  3. klient si vyziada notifikacie
  4. klient zobrazi notif
  5. klient uz len caka na nove notif…

A mas to oddelene, „lazy“, samostatna funkcionalita.

Este ma zaujima co znamena, ulozit do objektu. Ako pisal @srigi v PHP hento nedas. v ReactPHP ano ale skus si handlovat notif pre 100+ userov v pamati. Cize stale mi pride jedno query pre nacitanie napr. JSON objektu z DB pre notifikacie jedneho usera ako dobry deal.

AdamVyborny
Člen | 36
+
0
-

newPOPE napsal(a):

Tak ked tam mas len 100 pre 100 ludi tak to si na tom velmi dobre (moj nazor) vacsinou tych
Este ma zaujima co znamena, ulozit do objektu. Ako pisal @srigi v PHP hento nedas. v ReactPHP ano ale skus si handlovat notif pre 100+ userov v pamati. Cize stale mi pride jedno query pre nacitanie napr. JSON objektu z DB pre notifikacie jedneho usera ako dobry deal.

No myslel jsem ty proběhlé notifky z DB načíst do PHP objektu třeba usera abych je měl načtené celou dobu, do odhlášení uživatele, nehledě na refreshe a k nim přidával ty nové, co dorazí skrz websockety.

akadlec
Člen | 1326
+
+1
-

hmm. Nevím zda si už vyřešil. Ale to co chceš musíš řešit tak že když tu notifikaci vytváříš tak spustíš událost která tu notifikaci předá socketům. Imho na něco takového je Rabbit kanón na vrabce, Zero ti bude bohatě stačit. Když pustíš socketový server, tak se zároveň pustí se ZMQ consumerem a pak v appce kde ukládáš ty notifikace do DB pošleš zprávu přes ZMQ publishera. Consumer ji přijme, předá socketovému serveru a ten ji předá klientům.

@srigi no neřek bych nevýhoda. rabbit neměl pro mě význam tam cpát, ale stačí si vytvořit vlastní implementaci a pojede i rabbit. Pokud by ten interfejs nebyl uplně ok, tak stačí udělat PR :D Já přecházím na WAMPv2 tak pro mě to ztrácí význam

pheider
Člen | 1
+
0
-

@akadlec

akadlec napsal(a):

Když pustíš socketový server, tak se zároveň pustí se ZMQ consumerem a pak v appce kde ukládáš ty notifikace do DB pošleš zprávu přes ZMQ publishera. Consumer ji přijme, předá socketovému serveru a ten ji předá klientům.

Mohl bych poprosit o rozvedení výše uvedeného? Zajímal by mě nějaký konkrétní příklad, jak pushnout správu přes ZMQ z aplikace na Socket server s využitím https://github.com/iPublikuj/websockets. Pokouším se to rozchodit, ale zatím neúspěšně.

config.neon:

webSockets:
	routes:
		- '/chat/notify/<chatId>' : 'Chat:notify'

ChatController.php:

public function actionNotify($chatId)
{
    $topic = new Topic($topicUrl);
    $now = new \DateTime();
    $message = new \stdClass();
    $message->type = 'notification';
    $message->time = $now->format(DATE_ISO8601);
    $message->content = 'data';
    $topic->broadcast(Json::encode($message));
}

někde v aplikaci

<?php
/** @var IPub\WebSocketsZMQ\Pusher\Pusher $pusher */
$pusher->push(['notification'], 'Chat:notify', [$chatId]);
?>

Jedná se o správný postup?

JR
Člen | 5
+
0
-

Zdravím, mám problém s tímto řešením:
WebSocket server + ZMQ zdá se běží, server nalsouchá na správných portech a komunikaci naváže také správně, nicméně při push akci se mi do konzole webscoket serveru vrátí toto:

DEBUG: GET TOPIC /notifications/notification
INFO: Message was pushed to /notifications/notification topic
zend_mm_heap corrupted
DEBUG: Starting IPub\WebSockets
DEBUG: Launching WebSockets WS Server on: localhost:9005
INFO: ZMQ transport listening on 188.75.128.94:5555

Jakmile se snažím zprávu zapsat objeví se tato hláška: zend_mm_heap corrupted a server spadne, jelikož je v supervisorovi hned se zrestartuje a naběhne.

WebServer je v konfiguraci: Apache2 + PHP7.3-fpm + Debian 10

Našel jsem, že tato chyba má něco společného s opCache, zkoušel jsem různé konfigurace zvedat output_buffer nebo memory limity zkoušel sem v Apache envars vypnout alokování paměti Zendu ale také nepomohlo.

Nevím už moc co dělat jiného, napadlo mě, že by mohla být chyba ve verzích balíčků, jelikož je server čerstvě po updatu, a na verzi PHP7.2 + Apache2 + Debian 8 to normálně běhalo, při update sem musel purgnout apache, a nastavovat ho znovu komunikace z backendu aplikace běží přes ProxyPass ale všechny potřebné moduly jsem zapnul, a protože se komunikace naváže správně nemyslím si, že je problém v ní. Spíš si tedy nejsem jistý jestli ZMQ běží správně na PHP7.3 ale ZMQ jsem updatoval také do poslední verze.

Nevíte někdo?