Rails, mysql, ricerche e campi bloccati

Buongiorno, signori.
Dovrò realizzare un’applicazione per gestire l’agenda degli utenti da
chiamare da un contact center (tutto legale, sono clienti da contattare
prima che venga troppo tardi e chiamino tutti assieme gli ultimi 2
giorni utili :slight_smile: ). L’ipotesi era di usare mysql e rails come
interfaccia web, il funzionamento dovrà essere pressappoco così:
l’operatore arriva, riceve le direttive su chi chiamare (clienti del tal
paese, con le tali caratteristiche, ecc.), fa la ricerca, gli compare la
lista, clicca su un nominativo, si apre la pagina con le caratteristiche
(nome, cognome, numeri di telefono, ecc.), campi note, check vari
(chiamato, a posto, non risposto, scassasfere, ecc.), effettua la
chiamata, prende l’appuntamento se trova il tipo (su un’altra
applicazione), scrive le note e quello che deve sul profilo cliente,
salva, torna alla ricerca e via col prossimo.
Primo problema: se un operatore apre il profilo di un utente, gli altri
NON DEVONO essere in grado di fare la stessa cosa, in quanto è già in
“elaborazione”; in teoria si risolve coi blocchi sui record di mysql…
non li ho mai usati, ma me li guarderò. Se però qualcuno ha
suggerimenti, consigli, pezzi di codice avanzato o altro, mi dica pure
:slight_smile:
Secondo problema: ho notato che quando si fa una ricerca con ruby, i
dati dei campi trovati sono salvati nell’apposita variabile fino a che
non viene rigenerata. Il problema è che se lavora così e due operatori
fanno la stessa ricerca scegliendo entrambi “Pinco Pallino” (anche a
differenza di qualche secondo, non per forza nel medesimo istante), in
teoria entrambi dovrebbero ritrovarsi con la possibilità di modificare
l’utente, in quanto compare nella ricerca come non bloccato e potrebbero
esserci problemi di sovrascritture o peggio… ho visto bene, oppure mi
sono confuso?

Come sempre grazie in anticipo e a presto :slight_smile:

2009/1/19 Daneel O. [email protected]:

Primo problema: se un operatore apre il profilo di un utente, gli altri
NON DEVONO essere in grado di fare la stessa cosa, in quanto è già in
“elaborazione”; in teoria si risolve coi blocchi sui record di mysql…

non potresti semplicemente aggiungere un campo boolean
“in_elaborazione”, oppure un campo id
“utente_che_se_ne_sta_occupando_id”?

lo potresti settare quando l’utente clicca sul nome; se poi l’utente
per qualche motivo lascia perdere (non so se implementi questa
feature), ricambi il record, mettendo null nella colonna.

così resta ancora la possibilità teorica di concorrenza, ma è
estremamente ridotta, e per meno di 100 utenti che lavorano
contemporaneamente penso che difficilmente si
verificherà.
ciò non esclude l’uso di trucchetti mysql ma li rende meno indispensabili.

Secondo problema: ho notato che quando si fa una ricerca con ruby, i
dati dei campi trovati sono salvati nell’apposita variabile fino a che
non viene rigenerata. Il problema è che se lavora così e due operatori
fanno la stessa ricerca scegliendo entrambi “Pinco Pallino” (anche a
differenza di qualche secondo, non per forza nel medesimo istante), in
teoria entrambi dovrebbero ritrovarsi con la possibilità di modificare
l’utente, in quanto compare nella ricerca come non bloccato e potrebbero
esserci problemi di sovrascritture o peggio… ho visto bene, oppure mi
sono confuso?

aspetta.
se da applicazione web (ma anche da client mysql, a mano) fai una
query, di solito non la rifai ogni secondo, ti accontenti di leggere i
risultati. così, è inevitabile che una ricerca “invecchi”, anche solo
dopo pochi secondi. questo problema, di per sé, è irrisolvibile.

però, se quando l’utente decide di fare qualcosa con un certo record
tu cambi un valore del record stesso, come dicevo sopra, riduci il
tempo in cui può avvenire un problema a pochissimi istanti (il tempo
di un click, di solito molto meno di un secondo); sempre come sopra,
puoi anche utilizzare i lock del db per eliminare anche questo
rischio, che però, ribadisco, è quasi inesistente (di quanti
telefonisti stiamo parlando?)

su come poi si faccia, in mysql, a fare questi lock, mi spiace, non so
aiutarti.

Pietro G. wrote:

2009/1/19 Daneel O. [email protected]:

Primo problema: se un operatore apre il profilo di un utente, gli altri
NON DEVONO essere in grado di fare la stessa cosa, in quanto � gi� in
“elaborazione”; in teoria si risolve coi blocchi sui record di mysql…

non potresti semplicemente aggiungere un campo boolean
“in_elaborazione”, oppure un campo id
“utente_che_se_ne_sta_occupando_id”?

lo potresti settare quando l’utente clicca sul nome; se poi l’utente
per qualche motivo lascia perdere (non so se implementi questa
feature), ricambi il record, mettendo null nella colonna.

E’ stata la prima ipotesi presa in considerazione, ma c’è un problema:
se l’utente mi chiude la pagina (o finestra), addio cambio di valore sul
campo apposito, se invece si usano i controlli di mysql, in teoria
dovrebbe sbloccarsi. Ricordo che per ora in pratica so solo che esistono
e poco più, quindi se dico scemate correggetemi :slight_smile:

Secondo problema: ho notato che quando si fa una ricerca con ruby, i
dati dei campi trovati sono salvati nell’apposita variabile fino a che
non viene rigenerata. Il problema � che se lavora cos� e due operatori
fanno la stessa ricerca scegliendo entrambi “Pinco Pallino” (anche a
differenza di qualche secondo, non per forza nel medesimo istante), in
teoria entrambi dovrebbero ritrovarsi con la possibilit� di modificare
l’utente, in quanto compare nella ricerca come non bloccato e potrebbero
esserci problemi di sovrascritture o peggio… ho visto bene, oppure mi
sono confuso?

aspetta.
se da applicazione web (ma anche da client mysql, a mano) fai una
query, di solito non la rifai ogni secondo, ti accontenti di leggere i
risultati. cos�, � inevitabile che una ricerca “invecchi”, anche solo
dopo pochi secondi. questo problema, di per s�, � irrisolvibile.

Sì, questo lo so. Il mio dubbio è: se clicco su un utente della ricerca
per aprire la maschera di modifica, i dati che vedo sono quelli
“catturati” dalla ricerca (e quindi vecchi), oppure sono ricaricati dal
database (e quindi belli freschi)?
Ora che ci penso, potrei rifare una ricerca prima di visualizzare quel
dato… faccio un passaggio in più, ma sono più sicuro del dato non in
elaborazione da qualcun altro.

per�, se quando l’utente decide di fare qualcosa con un certo record
tu cambi un valore del record stesso, come dicevo sopra, riduci il
tempo in cui pu� avvenire un problema a pochissimi istanti (il tempo
di un click, di solito molto meno di un secondo); sempre come sopra,
puoi anche utilizzare i lock del db per eliminare anche questo
rischio, che per�, ribadisco, � quasi inesistente (di quanti
telefonisti stiamo parlando?)

I telefonisti saranno 5, niente di grosso, per fortuna… ah, se a
qualcuno interessa, ben venga a darmi una mano… e se siete a
conoscenza di qualcosa del genere già in funzione, ditemi pure dove
trovarla (per ora non ho visto niente che possa fare al caso nostro).

su come poi si faccia, in mysql, a fare questi lock, mi spiace, non so
aiutarti.

Vorrà dire che studierò da solo… sperando di capirci qualcosa ':slight_smile:

Il 19 gennaio 2009 11.43, Daneel O. [email protected] ha
scritto:

E’ stata la prima ipotesi presa in considerazione, ma c’è un problema:
se l’utente mi chiude la pagina (o finestra), addio cambio di valore sul
campo apposito, se invece si usano i controlli di mysql, in teoria
dovrebbe sbloccarsi. Ricordo che per ora in pratica so solo che esistono
e poco più, quindi se dico scemate correggetemi :slight_smile:
vero, non ci avevo pensato.

poiché continuo a non conoscere i meccanismi di lock, rilancio: dopo
un’ora dal settaggio di un capo di tipo datetime, sblocchi il record.
ma in effetti così diventa macchinoso.

Sì, questo lo so. Il mio dubbio è: se clicco su un utente della ricerca
per aprire la maschera di modifica, i dati che vedo sono quelli
“catturati” dalla ricerca (e quindi vecchi), oppure sono ricaricati dal
database (e quindi belli freschi)?
Ora che ci penso, potrei rifare una ricerca prima di visualizzare quel
dato… faccio un passaggio in più, ma sono più sicuro del dato non in
elaborazione da qualcun altro.

se usi rails, non c’è problema: quando clicchi, viene effettuata una
nuova request, e quindi rifatta la query (e anche se fosse
un’applicazione desktop lo farei comunque, perché non puoi sapere,
appunto, quanto tempo aspetterà un utente prima di cliccare su un
link).

Pietro G. wrote:

Il 19 gennaio 2009 11.43, Daneel O. [email protected] ha
scritto:

E’ stata la prima ipotesi presa in considerazione, ma c’� un problema:
se l’utente mi chiude la pagina (o finestra), addio cambio di valore sul
campo apposito, se invece si usano i controlli di mysql, in teoria
dovrebbe sbloccarsi. Ricordo che per ora in pratica so solo che esistono
e poco pi�, quindi se dico scemate correggetemi :slight_smile:
vero, non ci avevo pensato.

poich� continuo a non conoscere i meccanismi di lock, rilancio: dopo
un’ora dal settaggio di un capo di tipo datetime, sblocchi il record.
ma in effetti cos� diventa macchinoso.

Riesumo la discussione perché potrebbe interessare altri e anche per
vedere se ci sono eventuali alternative che qualcuno conosce.

Approfondendo ActiveRecord, ho visto che gestisce i lock, il problema è
che lo fa solo nel momento di modificare i dati, con gli strumenti
attuali non è possibile fare in modo che blocchi il record quando
l’utente lo richiama e lo sblocchi quando ha finito di lavorarci. Alla
fine ho trovato che tutti hanno adottato la soluzione a cui eravamo
giunti anche noi (io e il mio collega): tabellina in cui memorizzare
id_utente, id_operatore e timestamp e verificare su questa qualki utenti
da chiamare non comparissero bloccati. E’ una soluzione un po’ più
evoluta del semplice flag “bloccato” nel record dell’utente che permette
di fare piazza pulita di eventuali “sessioni” rimaste bloccate causa
uscita impropria dell’operatore grazie al timestamp: una ricerca di
quelli più vecchi di un tot seguita da eliminazione e si è a posto :slight_smile:
Uhm… si potrebbe mettere anche flag + timestamp direttamente sul
record utente… vedrò cosa è meglio.

Ciao!
Potresti postare la tua soluzione completa per risolvere questo problema
della concorrenza sui campi, potrebbe essere utile a molti!

Grazie!
Enrico

Enrico B. wrote:

Ciao!
Potresti postare la tua soluzione completa per risolvere questo problema
della concorrenza sui campi, potrebbe essere utile a molti!

Grazie!
Enrico

Wow, che emossione, una richiesta diretta di vedere il codice per
pubblica utilità ! :slight_smile:

Dopo la boiata, le cose utili.

Come lasciavo intendere, ho esaminato il caso e mi sono orientato per il
sistema semplice, cioè alla tabella coi dati da gestire ho aggiunto i
campi “bloccato” e “datablocco”, rispettivamente booleano e datetime.

Nelle ricerche ho aggiunto come parametro discriminante anche il valore
di “bloccato”, per cui ho qualcosa del genere:

class AgendaController < ApplicationController
codice codice…

def cerca

@contacts = Contact.find(:all, :from => “contacts”, :conditions =>
“[condizione1] and [condizione2] and bloccato=‘0’”)

end
codice codice…

Passando alla gestione vera e propria dell’apertura dei dati con
relativo blocco, acco qui che ho combinato:

def modifica
@contact = Contact.find(params[:id]) #naturalmente qui ci si arriva
dalla pagina “cerca” in cui come visto sopra saranno trovati solo i
contatti non bloccati
@contact.update_attribute(:bloccato, ‘1’)
@contact.update_attribute(:datablocco, “#{Time.now}”)
end

In questa maniera appena si carica la pagina si setta il blocco e si
scrive la data in cui è stato fatto. Quest’ultima servirà per sistemare
le cose in caso l’operatore faccia un’uscita non gestita… sì, si
potrebbe fare una ricerca per bloccato = 1, ma che succede se qualcuno
ci sta lavorando? Gli resettiamo i dati sotto i piedi? Con la data si
possono fare ricerche più mirate ed evitare macelli :slight_smile:

Siamo quindi dentro la pagina di gestione dei dati, bene, ora abbiamo
finito, si vuole salvare e “mollare” il record al resto del modo.
Io ho messo i parametri dentro la pagina "modifica.html.erb (la view
corrispondente, in pratica):



In questa maniera premendo l’apposito pulsante del form si
“cancelleranno” i valori di blocco, permettendo agli altri di poter
buttare all’aria tutto il nostro prezioso lavoro appena fatto :smiley:

Se a qualcuno interessa la gestione tramite una tabella separata, qui:
http://www.corprew.org/blog/2007/05/07/long-live-locks-part-1/ se ne
parla un po’… peccato non ci sia la parte 2 dell’articolo, ma penso
che non ci sia nulla di troppo astruso, tranne una gestione un po’ più
elaborata delle ricerche e dei salvataggi.

Spero di essere stato chiaro, in caso domandate se non mi sono spiegato
bene… e se fate di meglio, ditemelo che scopiazzo :slight_smile:

A presto.