Errore variabile globale

Salve a tutti.

Ho un problema un po’ strano, vorrei sapere se vi è mai capitato.

Nella mia applicazione ho una variabile $variabileglobale che assume
certi valori che valgono per tutti.

$variabileglobale viene aggiornata in determianti metodi, e letta poi da
altri metodi. Non posso metterla in session[variabile] perchè deve
essere leggibile anche dalle sessioni che non l’hanno creata.

Ora nel development environment va tutto OK, ma quando passo in
production
in alcune circostanze (non sempre) questa variabile non viene aggiornata
immediatamente ma dopo un po’ di azioni.

faccio un esempio

In DEVELOPMENT:

Controller1Azione1 --> $variabileglogale =“1”
Controller1Azione2 --> leggi $variabileglogale restituisce “1”
Controller1Azione3 --> $variabileglogale =“2”
Controller1Azione4 --> leggi $variabileglogale restituisce “2”
Controller2Azione5 --> leggi $variabileglogale restituisce “2”
Controller2Azione6 --> leggi $variabileglogale restituisce “2”

. . .

invece in PRODUCTION accade questo:

Controller1Azione1 --> $variabileglogale =“1”
Controller1Azione2 --> leggi $variabileglogale restituisce “1”
Controller1Azione3 --> $variabileglogale =“2”
Controller1Azione4 --> leggi $variabileglogale restituisce “2”
Controller2Azione5 --> leggi $variabileglogale restituisce “1”
Controller2Azione6 --> leggi $variabileglogale restituisce “2”

. . .

Come si vede Azione5, quando si passa ad un altro controller, il valore
di $variabileglobale è quello vecchio, ma poi nell’azione successiva
viene aggiornato.

Ora dopo averci perso la testa mi sono fatto l’idea che la cosa possa
dipendere dalle istanze mongrel del proxy balance (che ho in production
ma non ho in development)

In production il server apache fa il proxy balance tra due server
mongrel che girano su due porte diverse.
Potrebbe darsi che $variabileglobale assuma 2 valori diversi nelle 2
istanze di mongrel?

Se è così si spiegherebbe anche perchè alle volte funziona: dipende da
quale istanza mongrel il server apache va a prendere $variabileglobale
in quel momento.

Pero’ la cosa mi pare davvero strana.

Voi che ne dite?

Grazie a tutti!

Sam P. wrote:

Salve a tutti.

Ho un problema un po’ strano, vorrei sapere se vi è mai capitato.

Nella mia applicazione ho una variabile $variabileglobale che assume
certi valori che valgono per tutti.

$variabileglobale viene aggiornata in determianti metodi, e letta poi da
altri metodi. Non posso metterla in session[variabile] perchè deve
essere leggibile anche dalle sessioni che non l’hanno creata.

Ora nel development environment va tutto OK, ma quando passo in
production
in alcune circostanze (non sempre) questa variabile non viene aggiornata
immediatamente ma dopo un po’ di azioni.

[…]

In production il server apache fa il proxy balance tra due server
mongrel che girano su due porte diverse.
Potrebbe darsi che $variabileglobale assuma 2 valori diversi nelle 2
istanze di mongrel?

Se è così si spiegherebbe anche perchè alle volte funziona: dipende da
quale istanza mongrel il server apache va a prendere $variabileglobale
in quel momento.

E’ esattamente quello che succede. I due mongrel sono processi separati
che non comunicano in nessun modo (non consideriamo per ora il
database). Le variabili al loro interno non sono condivise e pertanto
devi progettare l’applicazione di conseguenza, senza assumere che una
variabile sia già stata preparata dall’altro server: ogni mongrel
dev’essere completamente autonomo. L’alternativa sarebbe memorizzare le
variabili globali in un qualche sistema centralizzato, magari usando
DRb, ma mi pare una sovraingegnerizzazione oltre che un
ammazza-performance…

Tieni presente che ci sono problemi pure con session[]. In particolare
fai attenzione alle race conditions, soprattutto in applicazioni Ajax
dove ci sono tante richieste contemporanee dallo stesso browser al
server. Può capitare che due richieste vadano a due mongrel differenti e
le modifiche alla sessione fatte da uno siano sovrascritte da quelle
fatte dall’altro.

Avevo avuto questo problema su SkipperMania (ricordate?) e l’ho risolto
in parte usando un plugin chiamato SmartSessionStore, una versione più
evoluta di SqlSessionStore, che aggiorna la sessione nel db solo se è
stata modificata, e in parte con una riprogettazione che evitasse
situazioni in cui tante richieste debbano aggiornare la sessione.
Un’alternativa sarebbe configurare il proxy in modo che mandi tutte le
richieste di una sessione allo stesso mongrel.

Come regola però meno si usa session[] e meglio è…

Paolo M. wrote:
[cut]

Come regola però meno si usa session[] e meglio è…

Buonanotte!!

Ma scusa un po’, allora io ho l’esigenza di trasferire dei dati da un
controller all’altro (per cui utilizzo session[]) e tra due sessioni
diverse ( per cui utilizzo $variabileglobale).

Ora, se non posso piu’ utilizzare nè session[] nè $variabileglobale,
come faccio?

Li potrei scrivere tutti nel DB, ma le performance?
Alcuni di questi dati vengono letti in tutte le azioni, il che
significherebbe continui accessi al DB…

Grazie di tutto.

Sam P. wrote:

Paolo M. wrote:
[cut]

Come regola però meno si usa session[] e meglio è…

Ora, se non posso piu’ utilizzare nè session[] nè $variabileglobale,
come faccio?

Ha detto che meno lo usi meglio è, non ha detto di non usarlo. Il punto
è che le session in realtà sono una cosa “finta”, non esistono. Se uno
disattiva i cookie non funzionano più. Meno ne fai uso meglio è, e se
non ne dipendi per niente sarebbe meglio ancora.

Li potrei scrivere tutti nel DB, ma le performance?

Che db hai? Puoi cachare tutto in memcached se il db diventa un collo di
bottiglia.

Alcuni di questi dati vengono letti in tutte le azioni, il che
significherebbe continui accessi al DB…

si… quindi? il db sta li a posta. Sinceramente dubito che tu abbia
tanti utenti da non poter fare una mezza dozzina di query per request.

Capisco lo scorcerto. Le sessioni sembrano una cosa così intuitiva ma in
realtà possono essere piuttosto complesse da gestire. Il problema è che
Rails dà molte scelte :slight_smile:

I dati nella sessione di Rails sono affidati ad un container, che in
Rails 2.0.2 per default mi pare le memorizzi in un cookie del browser
(sì, ci mette dentro proprio tutti i dati). Questo
significa che puoi usare al massimo 4k di dati serializzati e
codificati, quindi in pratica un po’ di meno.

Se non ti va bene usare un cookie o il limite sui dati è troppo basso
per le tue necessità , potresti usare il file
store (il default dell’environment di sviluppo di Rails 1.2), che
memorizza
i dati in un file in tmp/sessions. Il problema è che all’aumentare delle
sessioni le performance decrescono enormemente perché la directory si
riempie e il sistema operativo ci mette tanto tempo a trovare i file.
Inoltre se hai più macchine server senza un file system in comune, le
sessioni rimangono visibili solo all’interno di ogni singola macchina.

Per questa ragione normalmente i dati di sessione si memorizzano
proprio nel database, nella tabella sessions. Come container si usa o
l’ActiveRecord session store o con il Sql session store (più veloce).
Di conseguenza, se le sessioni non sono fatte da troppi dati, non è
molto diverso leggere i dati da sessions e decodificarli o rifare le
query all’inizio di ogni richiesta. Tra l’altro le query magari sono giÃ
in cache a memcached, se lo usi di fronte al db.

Ecco perché l’approccio raccomandato è tenere in sessione al più gli id
dei record e poi rileggere tutto dal db.

Ti consiglio queste letture:

Introduzione alle sessioni:
http://wiki.rubyonrails.org/rails/pages/sessions

Performance dei session container:
http://scott.elitists.net/sessions.html

Ottimizzazioni:
http://www.texperts.com/2007/05/01/race-conditions-in-rails-sessions-and-how-to-fix-them/
http://code.google.com/p/rails-fast-sessions/

Ciao
Paolo

Sam P. wrote:

Paolo M. wrote:
[cut]

Come regola però meno si usa session[] e meglio è…

Buonanotte!!

Ma scusa un po’, allora io ho l’esigenza di trasferire dei dati da un
controller all’altro (per cui utilizzo session[]) e tra due sessioni
diverse ( per cui utilizzo $variabileglobale).

Ora, se non posso piu’ utilizzare nè session[] nè $variabileglobale,
come faccio?

Li potrei scrivere tutti nel DB, ma le performance?
Alcuni di questi dati vengono letti in tutte le azioni, il che
significherebbe continui accessi al DB…

Grazie di tutto.

S2 akira wrote:

Ha detto che meno lo usi meglio è, non ha detto di non usarlo. Il punto
è che le session in realtà sono una cosa “finta”, non esistono. Se uno
disattiva i cookie non funzionano più. Meno ne fai uso meglio è, e se
non ne dipendi per niente sarebbe meglio ancora.

Va detto che per fare così bisogna progettare l’applicazione in un certo
modo. Visto che il contesto non c’è più, ci si deve affidare unicamente
alle URL.
Le letture consigliate sono quelle sul cosiddetto RESTful Rails, magari
iniziando dal tutorial http://www.railsforum.com/viewtopic.php?id=1068

L’autenticazione però di solito si appoggia proprio ai cookie, a meno di
mettere un’autenticazione HTTP davanti all’applicazione e poi leggere
gli user passati dal web server o realizzare qualcosa con i certificati
SSL. Non mi vengono in mente altre possibilità .

Ciao
Paolo

Paolo M. wrote:

S2 akira wrote:

Ha detto che meno lo usi meglio è, non ha detto di non usarlo. Il punto
è che le session in realtà sono una cosa “finta”, non esistono. Se uno
disattiva i cookie non funzionano più. Meno ne fai uso meglio è, e se
non ne dipendi per niente sarebbe meglio ancora.

Va detto che per fare così bisogna progettare l’applicazione in un certo
modo.

Bè, ovvio :slight_smile:

Visto che il contesto non c’è più, ci si deve affidare unicamente
alle URL.

Oppure autenticare gli utenti con certificati, oppure ancora usare ldap,
oppure kerberos, o… le opzioni non mancano, anche ovviamente andranno
a impattare sulle performance. chiaramente ci sono sempre pro e contro,
e personalmente uso sempre le session per memorizzarci una user_id.

L’autenticazione però di solito si appoggia proprio ai cookie, a meno di
mettere un’autenticazione HTTP davanti all’applicazione e poi leggere
gli user passati dal web server o realizzare qualcosa con i certificati
SSL. Non mi vengono in mente altre possibilità .

Concordo :slight_smile:

Paolo M. wrote:

[cut]

Grazie delle informazioni, provero’ ad utilizzare i vostri suggerimenti.

Tanto per puntualizzare il database è il DB2 della IBM e si trova su un
server diverso da quello in cui si trova il web server (con rails).
Quindi ogni accesso al DB viaggia tramite rete.

Come autenticazione utente utilizzo il plugin RESTful authentication.

Ora provero’ a scrivere tutto nel DB anche perchè non avevo pensato che
l’utente poteva disattivare i cookie: poi non funziona piu’ niente!

Non penso di avere problemi di performance per il mio attuale numero di
utenti, poi in futuro si vedra’.

L’unica cosa è che avendo il DB su una macchina diversa dal server web,
forse sarebbe il caso di scrivere questi dati nel file system di
quest’ultimo anzichè sul DB.

Con pochi utenti (come ora) è sicuramente più veloce, ma all’aumentare
del numero di utenti diventa più veloce l’utilizzo del DB2, anche se via
rete, perchè indicizza i record.

La cosa che mi pesa un po’ è il dover riscrivere tutto quello che avevo
gia’ fatto con $variabileglobale e session[] . . . .

Grazie di tutto.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs