ugrás a tartalomhoz

Long-polling terheléscsökkentés

pkadam · 2013. Okt. 1. (K), 22.35
Sziasztok!

Adott egy weboldal, ami long-pollinggal kérdez le információt a szerverről (pl. az új levelek, értesítések számát). Ha a felhasználó sok lapot nyit meg, akkor indokolatlanul sok párhuzamos kérést küld a szerver felé, miközben mindegyik lap ugyanazt a választ kapja meg - tehát elég lenne, ha egyszerre csak egy lapon történne AJAX-hívás.

A lekérések párhuzamosságát wildcard DNS-bejegyzés (*.example.com) biztosítja, így mindegyik egy véletlenszerű aldomainre mutat, tehát a böngésző nem korlátozza a párhuzamos lekéréseket.

Kérdésem, hogy szerintetek mi lenne a legjobb megoldás, hogy ilyen esetekben csökkenthessük a terhelést? A lapok egymás közti kommunikációjához süti, LocalStorage vagy SessionStorage merülhet fel (bár csak az előbbi kompatibilis a régebbi böngészőkkel). Egy lekérés küldésekor a szkript menthetné a böngészőben, hogy mikor indította a lekérést, és egy másik lapon csak akkor indul lekérés, ha ez régebben történt, mint a long-polling maximális hossza (sikernél vagy sikertelenségnél pedig törlődik az időbélyeg). Ha a felhasználó az éppen lekérést indító lapfület zárja be, akkor itt lehet kiesés, de a szkript akár másodpercenként is felülírhatja az időbélyeget, így ez kiküszöbölhető. A szervertől kapott válasz pedig szintén mentésre kerülne sütibe vagy SessionStorage-be, így az inaktív lapok ennek aktuális értékére támaszkodnának.

A felhasználónkénti terhelés csökkentése nélkül, ha mindenki megnyit 10 lapot, akkor néhány tíz látogató egyidejű bejelentkezése esetén már el is érnénk a szerver maximális párhuzamos kiszolgálási kapacitását.

Mit gondoltok?

Válaszotokat előre is köszönöm,
Ádám
 
1

Szerintem találj ki egy

inf · 2013. Okt. 1. (K), 22.43
Szerintem találj ki egy interface-t a kliensben tárolásra, aztán tedd be alá az összes szóba jöhető megoldást: localstore, cookie, etc... Utána használd azt. Amúgy facebook-nál érdemes lenne körülnézni, hogy a chat rendszerüket hogyan csinálják, ott is valami ilyesmi lehet a háttérben...

Nem csak a tárolás a probléma itt szerintem, hogyan döntöd el több lapnál, hogy már van e a localstore-hoz hozzárendelve long pollingos szinkronizáló, vagy sem? Pl ha valaki bezárja a lapot, amin az aktív szinkronizáló volt, akkor leáll a szinkronizálás. Erre is ki kéne találni valamit szemafort vagy ilyesmit, és folyamatosan kéregetni az erőforrást. Az erőforrás kiadását meg kb fogalmam sincs mi alapján lehetne eldönteni. :S Max a legutóbbi sikeres kérés időpontját lehetne lementeni, és ha már régen volt, akkor kiadni az erőforrást, de ilyenkor is előfordulhat, hogy két lap párhuzamosan kapja meg... Lehet még onbeforeclose-ra kötni az erőforrás felszabadítását, stb... Nehéz kérdés, sosem foglalkoztam vele...
2

IO loop

janoszen · 2013. Okt. 1. (K), 22.59
Ha csak annyi a feladat, hogy a klienseket ertesiteni kell a valtozasokrol, akkor ez semmilyen disk IO muvelettel nem jar, magyarul egyetlen processzben futo select/epoll loop megoldja a feladatot olyan laza 10k kliensig. A legalkalmasabb erre a feladatra a a NodeJS es a socket.io mivel megold egy csomo olyan alacsony szintu problemat is, amivel egyebkent kellene foglalkoznod (pl. hogy megszakadt a kapcsolat, de mivel nincs adatmozgas, nem veszed eszre), illetve megoldja a kompatibilitasi gondokat is.

Ugy latom, hogy nem a feladat van leirva, hanem igazabol egy konkret implementacio menten gondolkodsz. Ha ugy egyszerubb, csorogj fel valamikor Skype-on, mert ez tipikusan mar atmegy az architektura-tervezes kerdeskorebe.
3

A socket.io-t én is tudom

inf · 2013. Okt. 1. (K), 23.04
A socket.io-t én is tudom ajánlani. Ha jól tudom van benne valami fallback megoldás, arra az esetre, ha nincs websocket, de lehet, hogy rosszul tudom. Ezek szerint a kliens oldalon nem kell foglalkozni azzal, hogy több kapcsolat van nyitva?

Arra gondoltam, hogy vagy localstore-ban valahogy le kellene tárolni, hogy ki van osztva a szinkronizáló erőforrás, és tab bezáráskor felszabadítani, vagy ha már ki van osztva, akkor valahogyan megakadályozni, hogy újat nyisson egy másik tab, mondjuk ha egy domain-re csak egy kapcsolat lehet egyszerre nyitva, akkor a kapcsolatok limitálása pont jó lenne ilyen szempontból. A gond csak az, hogyha jól tudom egyszerre 4 vagy több kérés is mehet egyetlen domain-re. Hogy is van ez?
4

Körvonalazódik

pkadam · 2013. Okt. 1. (K), 23.35
Amikor egy lap betölt, és elindulna a szinkronizálás, lekérdezi localStorage-ból, hogy van-e 2 mp-nél frissebb időbélyeg és mentett szerverválasz.
1.) Ha van, használja az ottani értéket.
2.) Ha nincs, elindítja az AJAX-kérést, és a válaszig másodpercenként frissíti a timestampet.

A szinkronizálás időtartamára onunload eseménykezelőt kap az ablak (köszönöm, inf3rno, ez jó irány), ami törli a timestampet.

Mindegyik oldal pedig másodpercenként ellenőrzi az időbélyeget, és annak függvényében cselekszik.

Szerintetek?

A socket.io és a NodeJS virtuális post-iteken lebeg már jó ideje az arcom előtt, vastag piros betűkkel felírva :) Janoszen, köszönöm a lehetőséget – ha kicsit belekóstoltam már ezekbe, élni fogok vele.

Egyszerre 2-8 kérést engednek egy domainre a böngészők, emiatt álltunk rá a Facebookhoz hasonlóan a random hostokra – igaz, a session egy darabig beleszólt a párhuzamosságba a lockolással, de a gyors session_write_close() ezt is rövidre zárta :) A limitálás egyébként azért sem lenne szerencsés, mert az csak késlelteti a kérést, illetve többféle adat lekérése is felmerülhet, amit muszáj párhuzamosan kiszolgálni.

A 10k kliens egyidejű lekéréseit az adatbázis-szerver is ilyen vidáman fogadja?
5

Nem

janoszen · 2013. Okt. 1. (K), 23.47
Maradjunk annyiban, hogy PHP-bol nem akarsz long pollingot kiszolgalni. Szivni fogsz. Es nem fog mukodni random debuggolhatatlan esetekben ha van kozben egy proxy, egy hisztis tuzfal vagy BARMI. Nagyon nagyon nagyon sok erolkodessel TALAN mukodore lehet varazsolni, de a teljes koncepcio hogy varakozol egy TCP socketen arra hogy a tuloldal valaszoljon HIBAS mert nem kapsz rola ertesitest ha megszakad a kapcsolat. (A dolog szepsege: kiveve ha helyi gepen vagy, mert ott maskepp mukodik a TCP stack.)

Ami a NodeJS-t illeti, az otlet az egeszben az, hogy ha valami valtozik, akkor az adatbazis megkerulesevel direktben meglokod a NodeJS-t. Nyilvan lesz legalabb egy komponens aki tud a valtozasrol, hiszen valami beleirja a DB-be is. Tehat nem kerdezgetsz folyamatosan, hanem egy valtozas hatasara (Event vagy Edge) kuldesz uzenetet. Mivel a passziv varakozas nem eszik CPU-t, ez egeszen addig jol megy, amig bele nem futsz valami kernel limitbe, ami jellemzoen a C10K problema, azaz a 10e + connection problemaja.
6

A nodejs esetében a 10k

inf · 2013. Okt. 2. (Sze), 07.12
A nodejs esetében a 10k egyidejű kliens nem jelent 10k egyidejű adatbázis kapcsolatot... A kliensek csak a nodejs alkalmazáshoz kapcsolódnak, aminél beállíthatsz tetszőleges számú adatbázis kapcsolatot, amiket a kéréseidet fogod intézni... Kb úgy képzeld el, hogy php esetében az apache kiszórja a kéréseket külön process-ekbe és/vagy thread-ekbe, így párhuzamosítja a kéréseket, és emiatt minden egyes http kapcsolathoz külön adatbázis kapcsolatot kell nyitni, mert nincs erőforrás megosztás a http kapcsolatok között. Mivel a nodejs maga intézi a szerver dolgait is, ezért lehet erőforrás megosztás a http kapcsolatok között, csak egy magasabb absztrakciós szintre kell tenni a kódban az adatbázis kapcsolatok kiosztását... Ezt pl PHP-ban sosem fogod megcsinálni, max permanent connection-el, vagy ilyesmivel lehetne trükközni, vagy külön daemonnal, de ahhoz meg nem értek, meg ha jól tudom nem túl kényelmes az ilyesmi php-ban... Ugyanez a helyzet mondjuk a chat frissítésével. Mondjuk ha egy kód új üzenetet tesz a chatbe, akkor mivel a http kapcsolatok látják egymást (a socket.io-nál állandó kapcsolatok vannak), ezért nem kell lenyúlni az adatbázisig, hogy válaszolni tudj. Az eseményt nodejs szinten azonnal kiválthatod, nem kell adatbázis triggerrel, vagy bizonyos időközönkénti beolvasással trükközni... Szóval az ilyesmit egyáltalán nem a php-nek találták ki, mert az nem tud megfelelően állandó kapcsolatokat kezelni, egyszerűen nem arra találták ki, hanem sima http kérésekre. Abban mondjuk szerintem jobb, mint a nodejs, mert teljesen szinkron kódot lehet írni benne, nem kell aszinkron varázsolni, de pont emiatt megvannak a korlátai...
7

Átgondoltam a dolgot, ha

inf · 2013. Okt. 3. (Cs), 19.20
Átgondoltam a dolgot, ha egyetlen socket kapcsolatot akarsz minden tab-hoz, akkor ugyanaz lesz a probléma, mint ami a php-val volt, hogy a többi tab, és a letöltő tab között nincs közvetlen kapcsolat. Szóval ha lepusholsz valamit szerverről a kliensnek, akkor azt csak egy tab kapja meg közvetlenül, ami viszont nem tudja tovább pusholni a többi tabnak. Egyedül annyit tudsz tenni, hogy localStore-ba beszórod közösbe, és a többi tabbal a localStore-t figyeled ugyanúgy longpollinggal. Nem tudom ez mennyire erőforrás igényes, nem biztos, hogy jó ötlet mondjuk egy androidos mobilnál, vagy bármi ilyesminél... A localStore-ba érdemes egy event log-ot betenni, amit folyamatosan lekérnek az egyes tabok az időbélyegüknek megfelelően, és az abban lévő közös, vagy tabnak címzett eseményeket magukban is utólag kiváltják. Egyáltalán nem triviális ennek a megvalósítása, mert a localStore gondolom van annyira fapados, hogy nincsenek benne tranzakciók, így sosem tudhatod, hogy mikor ütközik két tab véletlenül mondjuk a felszabadult socket.io erőforrás elkérésében. Csinálni kell queue-t az ilyen közös erőforrásokhoz, azzal talán valamit lehet javítani a helyzeten, de még úgy sem 100%, hogy nem kapja e meg egyszerre két tab véletlenül...

A localStore-al kapcsolatos megállapításaim nem biztos, hogy igazak, nem használtam eddig localStore-t, de kb ilyen fapados adatbázisnak képzelem el, amiben nincs tranazkció kezelés, nincsenek triggerek, nincs állandó kapcsolat a tabok felé, nem tud saját függvényeket futtatni, stb... Nem hiszem, hogy ennél komolyabb lenne, de utána kell nézni... Annyi extra lehetőség lehet benne, hogy js függvényeket le lehet tárolni benne, és utána a tabokban egyesével lefuttatni, szóval nem muszáj mindent string-ben tárolni, és minden tab-ba betenni a logikáját... Elég lenne csak a socket.io-s tab-bal csomagoltatni, a többivel meg egy az egyben lefuttatni... Szerintem erre a long-pollingos localstore elérésre lehetnek kész pluginek kidolgozva, szal felesleges sajátot írni, inkább keresni kell.

szerk:

Úgy nézem, hogy van StorageEvent, ami gyakorlatilag a triggernek felel meg, és amin keresztül elméletileg jelezni lehet minden tab-nak, hogy változott valami az adatbázisban. Így viszont nem feltétlen kell longpollingozni, ha az onbeforeunload működik a böngészőben, akkor arra rá lehet kötni egy StorageEvent-et, és értesíteni minden tabot, hogy felszabadult a socket.io-s erőforrás, amivel nodejs-től kéred le az adatot. Ha nincs localstore, akkor sajnos marad a longpolling-os megoldás cookie, vagy bármi egyéb felé, de akkor már szerintem jobb inkább minden tab-nál külön socket-et nyitni a szerver felé, kevesebb a befektetett munka. Teljesen attól függenek a lehetőségek, hogy milyen felhasználói rétegre tervezel, és azoknak milyenek a böngészőik...

szerk2:

http://blog.fastmail.fm/2012/11/26/inter-tab-communication-using-local-storage/

Itt írnak long pollingos localstore kommunikációról. Amit persze itt nem long pollingnak neveznek, de mindegy, szóval nem közvetlen event-es, hanem pingelős...

A storage event témának még jobban utána kell néznem.

Ami még esetleg szóba jöhet az a shared webworkers, amiről eddig nem sokat találtam, de elvileg jó ilyesmire... Annak is utána kell néznem...
8

Szerver

janoszen · 2013. Okt. 3. (Cs), 22.16
Szerveren keresztul is uzenhetsz a masik tabnak, mivel hozzafersz a sutikhez, eleg egyszeru eldonteni ki kivel van.
9

Ja, de pont arról volt szó,

inf · 2013. Okt. 3. (Cs), 22.50
Ja, de pont arról volt szó, hogy hogyan csökkentsük a szerver terhelését...

Az igazi az lenne, ha egy webworkert lehetne indítani úgy, hogy ahhoz minden kérdéses tab hozzáfér, és csak akkor állna le, ha az összes tab bezárult. Nem tudom, hogy erre mennyire van lehetőség, szerintem semennyire, de utánajárok. Egyelőre az a benyomásom, hogy a webworkerek csak a nyitó ablakukkal tudnak kommunikálni, és annak bezárultakor elvesznek.
11

IO

janoszen · 2013. Okt. 4. (P), 01.05
Igen, a szerver terhelését kell csökkenteni, de nem mondta senki, hogy az átvitt adatmennyiségnek csökkennie kell. Ne ugorjunk át lépéseket a probléma megoldásában ha lehet. A helyes megoldás itt mindenképp NodeJS-hez hasonló megoldások, mert azoknál nem kell kliensenként külön processzt indítani. Minden más csak hack és jó ha nemárt többet mint amit használ.
12

Nem igazán értem, hogy mire

inf · 2013. Okt. 4. (P), 01.48
Nem igazán értem, hogy mire akarsz kilyukadni... A két megoldás kiegészíti egymást, és mindkettő csökkenti a szerver terhelését. Én elsőnek mindenképp a kliens átírását javaslom intertab resource sharing-esre, és ha az nem elég, csak akkor a váltást nodejs-re. Sokkal kevesebb munkával jár így...
13

Pl

janoszen · 2013. Okt. 4. (P), 11.59
Pl arra, hogy a localStore szinkron mukodesu, ergo ha irsz vagy olvasol benne, akkor addig nem fut tovabb semmilyen kod. Ez csomo szivast tud okozni. Nem beszelve a kompatibilitasi gondokrol, stb. Elmeletben tok egyszerunek hangzik, gyakorlatban viszont csomo energiat kell forditani ra ha nem akarod, hogy a userek x szazalekanak ne mukodjon. Nem veletlenul oldjak meg az ilyen kerdeseket inkabb szerveren.
14

A programozó kezében van a

Hidvégi Gábor · 2013. Okt. 4. (P), 12.10
A programozó kezében van a kontroll, a fenti linken olvasottak tudatában majd nem szemeteli tele a közös tárat, és nem lesznek ilyen gondjai. A kompatibilitási gondokra vannak már biztosan rutinkönyvtárak, az IE-ben bő egy évtizede van már hasonló megoldás.
16

Ertelmetlen

janoszen · 2013. Okt. 4. (P), 12.23
Eleve ertelmetlennek tartom az ezen valo erolkodest, mert ha mar 10k koruli konkurens (!) user van az oldalon, akkor el kell gondolkozni eroteljesen az egesz infrastrukturan. Arrol nem beszelve, hogy az atlag user azert nem tart ugyanabbol az oldalbol tobb tabot nyitva, szoval elozetes meresek hianyaban nem erzem ugy, hogy a problema valos lenne.
18

Kompatibilitással nincs

inf · 2013. Okt. 4. (P), 20.31
Kompatibilitással nincs akkora probléma, a szinkron működésre viszont jelenleg tényleg nincs megoldás. Max ha webworker-be lehetne tenni, amit meg ugye nem lehet :S Imét egy példa arra, hogy mennyire impotens a webes szabványokat, fejlesztéseket kitaláló gárda, kicsit se gondolnak bele, hogy amit csinálnak az használható e a gyakorlatban...

Úgyhogy ja, marad a php cseréje nodejs-re, vagy tornadora, vagy bármi hasonlóra, kinek melyik nyelv a szimpatikus...
19

Ha beteszem egy setTimeout-ba

inf · 2013. Okt. 4. (P), 23.37
Ha beteszem egy setTimeout-ba vagy egy iframe-be, az nem oldja meg ezt a sync blocking problémát?
22

Pl arra, hogy a localStore

tgr · 2013. Okt. 6. (V), 10.46
Pl arra, hogy a localStore szinkron mukodesu, ergo ha irsz vagy olvasol benne, akkor addig nem fut tovabb semmilyen kod.


Ez ebben a formában nem igaz, a localStorage-t lapbetöltéskor memóriába tölti minden böngésző, és gyakorlatilag azonnali az írás/olvasás, az első beolvasás az, ami blokkolhat. NC Zakas írt egy jó összefoglaló cikket a témában, aminek a végkövetkeztetése az, hogy ésszel használva nem okoz problémákat. (Ld. még: localStorage: Use it, Don't Abuse It)
23

Van még a WebSQL, ami viszont

inf · 2013. Okt. 6. (V), 11.16
Van még a WebSQL, ami viszont aszinkron, tehát biztosan nem blokkol. Az egyedüli probléma vele, hogy ff, msie jelenleg nem támogatja...

LocalStorage-nél a szinkron működés szerintem is csak nagyobb adatmennyiségnél okozhat komolyabb akadást. Ha ésszel használják, és nem akarják a teljes adatbázist localStorage-be tenni, akkor nem okozhat gondot...
24

A böngészők egyik fele a

tgr · 2013. Okt. 6. (V), 18.29
A böngészők egyik fele a WebSQL-t támogatja, a másik fele az IndexedDB-t, biztos van rá valami plugin, ami egységes felületet tesz a kettő fölé.
25

Passz, én már feladtam :D

inf · 2013. Okt. 7. (H), 05.32
Passz, én már feladtam :D
26

http://jaydata.org/

inf · 2013. Okt. 7. (H), 05.34
15

Ha minden long pollinghoz

tgr · 2013. Okt. 4. (P), 12.11
Ha minden long pollinghoz nyitva tartasz egy külön PHP szálat, az azt jelenti, hogy egyszerre max. annyi user használhatja az oldaladat, ahány szálat a szervered elbír (egy átlag szervernél ez néhány tíz, talán néhány száz lehet). Ez egy tab / user esetén sem egy hosszan fenntartható állapot.
10

Én arra jutottam, hogy

inf · 2013. Okt. 3. (Cs), 23.39
Én arra jutottam, hogy sok megoldás van a problémára, a cookie a leginkább támogatott, a localStorage az eggyel kevésbé, a window.postMessage még kevésbé, és a shared WebWorker a legkevésbé. Attól függően, hogy milyen böngészőket akarsz támogatni, kiválaszthatod a neked megfelelő megoldást.

Itt összeszedtem mindent, ami használható a témában:
http://stackoverflow.com/questions/19125823/how-is-it-possible-to-share-single-js-resource-between-browser-tabs/19165781#19165781

Jelenleg, amit javasolni tudok, és ami a legkevesebb erőfeszítéssel jár az az: intercom.js. Most kérdezgetem őket, hogy csak socket.io-t lehet e megosztani vele, vagy van e lehetőség long pollingra. Ha nagyon böngésző kompatibilis akarsz lenne, akkor építsd fel a saját rendeszered ez alapján, és használj cookie-t a BNC Connectorral.
17

Ha abból indulsz ki, hogy egy

Hidvégi Gábor · 2013. Okt. 4. (P), 12.24
Ha abból indulsz ki, hogy egy felhasználó általában egyszerre csak egy tabot nézeget, a többit elég csak akkor frissíteni, amikor átvált rájuk.

Ha ez nem kielégítő megoldás, akkor az értesítéseket küldheted nyugodtan az aktív ablakba, pl. az alján lehetne egy állapotsor, ahova kiírhatnád, hogy az egyébb nyitott tabjain van-e változás. Ha van, átvált, az pedig automatikusan frissít.

Ez utóbbi amiatt is célszerű, mert a másik tabokon csak úgy tudod jelezni a változást, hogy az oldal title-jét írod át, amit vagy érszrevesz vagy nem (pl. sok tabot nyit meg egyszerre, és nem férnek ki egy képernyőre, mert a böngészőt így csinálták meg). Az állapotsávon például egy csodálatos animációval fel tudod hívni a változásra a figyelmet.
20

Kód

pkadam · 2013. Okt. 5. (Szo), 19.52
Jelenleg így néz ki a JavaScript-kód, kliensenként 10 másodpercenként kérdezi a szervert, és 1 másodpercenként nézelődnek a tabok a localStorage-ban, ezt valószínűleg ki lehet váltani storageEvent-es eseménykezelővel, így a kliensre jutó terhelés is tovább csökkenthető.

A kérések szerveroldali kezelése nem long-polling, mert az PHP-vel hosszabb időre lefoglalna egy szálat, ami nem túl gazdaságos, a későbbiekben ezt socket.io-val tudjuk tovább optimalizálni, de egyelőre 1000 online felhasználó esetén ez másodpercenként 100 lekérés lenne, aminek elviekben nem szabadna gondot okozni. Ennél több user mellett pedig már bőven bele kell férnie az infrastruktúra bővítésének. (Lévén egy Apache szerver úgyis csak 200-400 párhuzamos kérést tud fogadni.)

Még felmerült ötletként, hogy Memcached-ben tárolnánk a bejelentkezett felhasználókat érintő értesítéseket, ami cronból frissülne, de ezzel alapvetően csak az adatbázisra jutó terhelést csökkentenénk. Érdemes ezzel foglalkozni?

function sync() {
	localStorage.setItem('sync',1);
	//console.log('SYNC STARTED.');
	window.onunload = function() { localStorage.setItem('sync',0); };
	$.ajax({
		url:			'http://channel-'+Math.round(1000+Math.random()*8999)+'.example.com',
		type:			'GET',
		dataType:		'json',
		crossDomain:	true,
		xhrFields:		{
							withCredentials: true
						},
		success:		function(data) {
							if (data.error == 'Not logged in.') {
								localStorage.setItem('autologout',true);
								return;
							}
							//console.log('RECEIVED DATA: ' + data);
							localStorage.setItem('messages',data.messages);
							localStorage.setItem('timestamp',timestamp());
						},
		error:			function(data) {
							//console.log('ERROR OCCURED DURING SYNC.');
						},
		complete:		function() {
							localStorage.setItem('sync',0);
							//console.log('SYNC DONE.');
							window.onunload = '';
						}
	});
}

function update() {
	if (localStorage.getItem('timestamp') < loaded) {
		//console.log('NOT UPDATED (DATA IS OBSOLETE: ' + (loaded - localStorage.getItem('timestamp')) + ' SEC OLD).');
		return;
	}
	//console.log('TRYING TO UPDATE...');
	var messages = localStorage.getItem('messages');
	
	if (messages != 0) {
		//console.log('FOUND '+messages+' MESSAGES.');
		if ($('#menu_messages span').length) {
			$('#menu_messages span').html(messages);
		}
		else {
			$('#menu_messages').append($('<span>').html(messages));
		}
		$('#menu_messages').prop('title','Üzenetek (' + messages +' új)');
		$('link[type="image/x-icon"]').replaceWith('<link rel="shortcut icon" type="image/x-icon" href="/img/favicon_notification.ico" />');
		document.title = '(' + messages + ') ' + siteTitle;
	}
	else {
		//console.log('NO MESSAGES FOUND.');
		$('#menu_messages span').remove();
		$('#menu_messages').prop('title','Üzenetek');
		$('link[type="image/x-icon"]').replaceWith('<link rel="shortcut icon" type="image/x-icon" href="/img/favicon.ico" />');
		document.title = siteTitle;
	}
	//console.log('UPDATE DONE.');
}

function initSync() {
	if (localStorage.getItem('autologout')) {
		clearInterval(syncID);
		window.location.assign('/?autologout&redirect='+encodeURIComponent(window.location.pathname));
		return;
	}
	if (timestamp() < Number(localStorage.getItem('timestamp'))+10) {
		//console.log('---SYNC NOT YET NEEDED---PLANNED IN: '+(10-(timestamp()-localStorage.getItem('timestamp')))+' SEC---');
	}
	else if ((!localStorage.getItem('sync') || localStorage.getItem('sync') == 0)) { //  && timestamp() > Number(localStorage.getItem('timestamp'))+10
		sync();
	}
	else {
		//console.log('---SYNC PENDING---');
	}
	update();
}

function timestamp() {
	return Math.floor((new Date().getTime()) / 1000);
}

document.domain = 'example.com';
siteTitle = 'Website Name'
loaded = timestamp();
localStorage.clear();
localStorage.setItem('timestamp',loaded);
localStorage.setItem('messages', <?php echo $new_messages; ?>);
syncID = setInterval(initSync,1000);
update();
21

Ha nincs sok adat egyszerre,

inf · 2013. Okt. 5. (Szo), 22.03
Ha nincs sok adat egyszerre, akkor a localstore teljesen jó, nem akasztja meg sokáig az oldalt. Storage event-et kipróbálnám a helyedben, egyszerűbb lesz tőle a kód. Nagyjából úgy jó, ahogy írtam, hogy a szerver kapcsolat tulajdonos tab ír a localstorage-be, hogy igen, még jelen van, a többiek meg nézik a storage event-et, aztán ha elmarad, akkor átveszi valamelyik a kapcsolatot. Az üzenet feldolgozó része az egy az egyben mehet storage event-be, annyi extra, hogy a szerver kapcsolat tulajdonos tab-nál nem vált ki eseményt, úgyhogy ott külön kell meghívni a frissítést, a többinél meg storage event listener-ből. Azt hiszem írni fogok erre általános kódot, meg megpróbálom tesztelni a sync kérések miatti blokkolást, hátha ki lehet küszöbölni valahogy...

Az adatbázissal csak akkor foglalkozz szerintem, ha kiderül, hogy az a szűk keresztmetszet valamilyen téren. Addig felesleges.
27

Storage event

pkadam · 2013. Okt. 7. (H), 06.02
A storage event-tel lett megoldva, ami IE-ben és Chrome-ban egy kis plusz odafigyelést igényel.

Az IE – egyedüliként – az érték megváltozása előtt küldi az eventet, tehát egy rövid setTimeout kell az új érték lekérdezéséhez.

A Chrome-ban pedig van egy lassan 3 éve (!) jegyzett bug: a document.domain módosítása esetén (aldomainről a root domainre) nem működik a localStorage eseménykezelője, tehát ilyen esetben rendszeresen le kell kérdezgetni az adott kulcs értékét.
28

Ezért gyűlölöm a kliens

inf · 2013. Okt. 7. (H), 06.39
Ezért gyűlölöm a kliens oldalt, gyakorlatilag semmi sem garantált vele, és a munka nagyrésze workaround-ok készítésével telik... Ha nem lenne jquery és társai bele se kezdenék kliens oldali fejlesztésbe.
29

Van-e ertelme?

janoszen · 2013. Okt. 7. (H), 12.03
Ezert kerdezem, hogy van-e ertelme? Eleg nagy osszegben mernek fogadni, hogy a kerdezo problemajat kulonosebb erolkodes nelkul meg lehet oldani szerver oldalon.
30

Részben

pkadam · 2013. Okt. 7. (H), 19.27
Egy részét igen, a szerveroldali JS jelentősen csökkenti a terhelést. A tabok közti azonnali kommunikációt (párhuzamos lekérések kiküszöbölése ill. a szerverválasz bedobása a közösbe) viszont praktikusabb helyben elintézni. Persze, megoldhatónak megoldható szerveroldalon is, amennyiben minden lapfül folyamatosan long-pollingol, de ezt egyáltalán nem tartanám optimálisnak.