Nisam još tako nešto radio sa PHP-om, a kada bi tako i dizao druge procese, nisam siguran da bi sa tim procesom mogao poslati informaciju prma klijentu.
Nije mi to bio cilj, nego mi se bilo glupo raspisivati ako baš nikoga ne zanima tema…
Uglavnom, koristio sam vrlo basic stvari, tj. samo AJAX i tehniku Long Polling, tko ne zna o čemu je riječ, to je tehnika gdje pošaljemo ajax request na server, ali server ne odgovara odmah nego drži otovoren request dok god se ne pojavi potreba da obavijesti klijenta o nečemu. Na taj način smo zapravo omogućili da server trigira moment kada želi poslati informaciju klijentu.
E sad, kako sam pomoću te tehnike postigao obostranu komunikaciju sa mogućnosti slanja paralelnih poruka i da komunikacija preživljava i reload stranice …
Znači osnovna ideja je:
Client šalje ajax request
Server drži request dok ne poželi poslati poruku klijentu
Klijent kada primi response (poruku), on podiže novi php proces, slanjem novog ajaxa.
Na taj način smo omogućili kontinuiran prijenos informacije sa servera na klijenta.
No moja tedencija je bila da napravim da php klasa upravlja “živim” varijablama tijekom cijele komunikacije, a kako se php proces završava kod slanja svakog odgovora, tako se restoraju i sve varijable. Preživljavanje varijabli je riješeno zapisivanjem static stanja na HDD od kuda ih novi proces oživi, pa unutar Pulse klase imamo osjećaj da proces cijelo vrijeme živi. (Iako se php procesi izmjenjuju) Problem kod ovoga je da sve treba uskladiti, jer ako će procesi paralelno ažurirati static varijable, može doći do gubitka podataka.
Tako da je prvi problem bio kako izvesti da client može poslati paralelno poruku dok Pulse-resolver živi.
Naime, klijent kada pošalje poruku na server, tj. kada podigne paralelni ajax request, taj request zna da je Pulse-resolver živ i čeka da se aktivni ciklus resolvera završi.(Ujedno javi resolveru da se aborta, kako bi se on mogao ubaciti)
Resolver tako na kraju svog ciklusa se aborta, spremi sva static stanja u HDD, a zadnji Ajax request preuzme njegovu ulogu i ujedno prosljedi resolveru poruku koju je client poslao. Taj novi resolver oživi sva static stanja svog prethodnika, pa unutar php Pulse klase imamo osjećaj da se sve kontinuirano dešava.
Na ovaj način možemo imati koliko god paralelnih poruka poslanih istovremeno, ona će jedna po jedna čekati svoj red da se ubace, tj. da preuzmu taj proces resolvera. Mi tako unutar Pulse klase, imamo osjećaj da upravljamo samo jednim resolverom. Iako on crkne/oživi po dolasku svake poruke.
I to je skoro pa sve, no ima jedan problemčić.
Da bi resolver kontinuirano mogao raditi, on mora sam sebe oživiti nakon svake poslane poruke.
To sam već objasnio: resolver šalje poruku na klijenta (time on crkne), client nakon što primi poruku, vrati ajax request koji ponovno oživi resolver i on tako nastavlja svoj posao …
No problem je u tome, ako se desi da klijent iz bilo kojeg razloga postane nedostupan (offline, stranica se reloada, ili nešto treće??) …onda će resolver ostati “mrtav” nakon što pošalje svoju zadnju “deadly” poruku. (Neće ga imati tko oživiti)
A kako je ovdje resolver vodeći igrač, mi želimo (ako želimo) da on obavlja svoj posao neovisno o tome jel klijent privremeno nedostupan.
Ovo je rješeno na sljedeći način:
Client kada otvara kanal komunikacije, kod prvog ajax requesta šalje još jedan ajax request. (Nazivam ga bulk request). Taj bulk request služi kao safe guard za slučaj da resolver crkne uslijed nedostupnog clienta kod slanja svoje zadnje “deadly” poruke.
Znači bulk radi sljedeće:
- prati jel resolver živ
- ako resolver ne pokaže znakove aktivnosti neko (zadano) vrijeme, bulk ga smatra da je crkao i preuzima njegovu ulogu. Znači oživi static varijablu (koja je uredno spremljena kod isporuke zadnje “deadly” poruke) i nastavlja posao resolvera tamo gdje je on stao.
No bulk se ponaša malo drugačije, on ne smije poslati poruku na klijenta, jer će i on crknuti ako je klijent i dalje nedostupan. Tako da resolver dok je u bulk modu, neće slati poruke na klijenta nego će sve poruke koje bi bile poslane, spremat će ih u svoju bulk listu…i to će raditi onoliko dugo dok:
- mu ne istekne zadani timeout
- dok ga ne ugasi logika unutar samog resolvera (posavljena od onoga tko koristi Pulse klasu)
- ili dok ne shvati da je klijent opet živ.
No bulk proces ne može niti direktno shvatiti da je klijent živ, niti on više može poslati poruku na klijenta, jer ako je bulk preuzeo proces koji je crkao zbog nedostupnosti klijenta, onda i ovaj bulk više nema tu konekciju po kojoj je nastao…
Pa klijent ako se vrati u život i ako pokrene isti kanal, taj prvi ajax request koji podiže kanal komunikacije će shvatiti da je bulk mode aktiviran i napravit će sljedeće: Vratit će poruku klijentu da je bulk mode aktivan i da treba u pozadinu staviti novi bulk da bude safe guard. Klijent tako primajući tu poruku šalje pojačanje, šalje i novi bulk request i novi ajax request koji će nastaviti život resolvera. Kada oni dvoje stignu na server, kažu aktivnom bulk resolveru da je sve ok i da se sada može ugasiti. Pričekaju da bulk resolver završi svoj trenutni ciklus i da se zagasi, preuzmu sve prikupljene poruke u bulk listi (opet preko HDD-a) i sve te poruke pošalju na klijenta. Klijent tako prima sve poruke koje su se desile dok je bio nedostupan. (Na programeru je kako će hendlati te poruke, ali one se nisu izgubile) …i od tog trenutka proces se opet uredno nastavlja, imamo novi safe bulk koji opet dežura da spasi stvar po potrebi i ajax requestove koji se naizmjenično izmjenjuje i razmjenjuje poruke.
Evo i jednostavna primjer kako to radi u praski:
Ovdje je setup sljedeći:
Pulse resolver ima zadatak da u svakom svom ciklusu podigne brojač za jedan i dobiveni broj pošalje kao poruku na klijenta.
Klijent ima zadatak da ispiše svaku poruku koju dobije, tako dobijemo brojač koji ispisuje niz: 1,2,3,4,5,6,7,8,9,…
E sad, ja na 9 reloadam stranicu i nakon reloada pokrećem isti kanal komunikacije. Nakon ponovnog pokretanja kanala dobivamo istovremeno poruke 10,11,12,13,14 i nakon toga nastavlja se dalje odbrojavanje.
Poruke 10,11,12,13,14 su one koje je resolver slao dok smo mi bili nedostupni i poslao ih je kod našeg spajanja na isti kanal…i od tuda se proces komunikacije dalje nastavio po već zadanom setupu scene.
Zašto se nije više brojeva prikupilo prilikom reloada stranice, zato jer je bulk čekao 3 sekunde dok shvati da je resolver crkao i tek tada je nastavio njegov posao. Taj delay u većini sučajeva ne predstavlja problem, dok bi gubitak informacije itekako predstavljao.
Ovime je upravo to postignuto. Kanal komunikacije koji preživljava reload klijenta. Vjerujem da bi se sa nekim drugim backand jezicima ovo izvelo daleko jednostavnije, ali onda nebi bilo ovoliko zabavno, hehe.