Applicazioni realtime

E’ possibile lanciare un comando facendo in modo che una richiesta get o post venga eseguita in un determinato secondo, a prescindere dal fatto che vi siano o meno utenti autenticati nella mia applicazione?

Supponiamo di avere una tabella in cui si trovano delle query ed il momento in cui devono essere eseguite. Io vorrei poter dire in quale secondo deve essere eseguita la query. La prima cosa che mi viene da fare è salvare query e timestamp di esecuzione.


$oraesecuzione = date("Y-m-d H:i:s", mktime() + 44);

A questo punto, ad ogni richiesta della pagina, controllerei tutti i record di quella tabella. In base al tempo, saprei quali e quanto saranno da eseguire.

L’algoritmo funziona. Lo sto già provando. Però mi sembra poco performante. I mean: se siamo connessi in 1000 su un sito, ogni volta che uno fa una richiesta … controlla sta tabella ed esegue quello che deve eseguire. Ha senso?

No. Così non va bene.

Devi creare un controller dedicato e nascosto a tutti gli altri 1000 utenti (magari protetta da ip, che la possa eseguire solo 127.0.0.1)

e poi scheduli l’esecuzione di questa pagina mediante crontab (però secondo me ogni secondo è un esagerazione. Puoi fare ogni 15 min)

Esatto… uno script PHP non gira permanentemente, viene eseguito solo quando lo richiami, quindi è dipendente dal fatto che utenti visitino o meno il sito. Se vuoi essere indipedente da eventuali utenti, puoi pianificare con un cron l’esecuzione dello script. Oppure puoi abbandonare PHP in favore di servlet Java :D

A questo punto uno dei 2 si merita il +

Ho risolto ficcando del codice in ogni richiesta:

In pratica il più delle volte non accade nulla. Ho una pagina che si aggiorna ogni 5 secondi … (ogni 5 secondi fa una richiesta json che aggiorna la pagina). In quelle richieste può sempre accadere qualche cosa.

Il problema viene quando ci son più utenti che interagisco sul db. Così ho usato le transazioni.




        $connection = Yii::app()->db;

        $transaction = $connection->beginTransaction();

        try {

            $lavori = $connection->createCommand($sql1)->queryAll();

            $connection->createCommand($sql2)->execute();

            $lavori = $connection->createCommand($sql3)->execute();

            $transaction->commit();

        } catch (Exception $e) {

            $transaction->rollBack();

        }



Potresti anche utilizzare cron se puoi…

Cron ha una precisione di un minuto (da quello che ho letto). A me serve la precisione al secondo. Di fatto lo stato di una pagina può cambiare da un secondo all’altro.

Sto anche pensando di fare un hack pazzesco, tipo usare la shared memory di php. In pratica gli script php possono usare una propria memoria condivisa a livello di server. Ne db ne file di testo. Sto facendo qualche esperimento … se mi capita di produrre qualche cosa di interessante vi propongo degli snippet di codice. Anche se non so bene come sfruttare questo lato di php.

Mi sembra di ricordare che l’oggetto cache di Yii ti permette di condividere informazioni a livello applicazione in modo che sia accessibile a tutte le istanze php.

Poi se la cache la memorizzi su database è anche scalabile tra più server se sincronizzi mysql.

Sulla schedulazione ogni secondo puoi fare uno script php che si avvia una tantum all’avvio del server e fa ciclo infinito ogni secondo mettendo alla fine di ogni ciclo una pausa php (usleep) oppure invece di usare crontab ti fai uno script che avvii come demone allo startup che fa sempre ciclo infinito e richiama ogni secondo lo script php (il ciclo stavolta è nell’SH invece che nel php).

E non ho rischi di timeout? Cmq proverò entrambe le soluzioni. Grazie per ora.

gasp mi interessa molto questa discussione.

Io ho la necessità di farmi un demone in php che legga una tabella ‘queue’, se non è vuota deve fare una serie di elaborazione, altrimenti ‘rimanere in attesa’.

Come si realizza ?

Tenete conto che il servizio deve essere fault tolerant. Se lo script dovesse andare in crash devo trovare il modo di farlo ‘risorgere’

Dal punto di vista del database, puoi usare le transazioni. Per il resto, in genere si usa un cronjob che periodicamente richiama una certa pagina php. Il resto dipende da te.

mmhh .è proprio ‘il resto’ il problema … il fatto è che una esecuzione ogni minuto è troppo poco

vorrei che facesse una cosa del tipo




while(1) { ... alcune cose sulla coda, da pochi ms }



poi mi sono detto… come faccio se va giu ?

allora… potrei fare si che lo script ogni minuto, quando viene lanciato, controlla se ‘se stesso’ è già in esecuzione… ma come si fa?

dal db deve solo leggere e cancellare, quindi se va in crash, a livello di db non succede proprio nulla, da quel punto di vista l’app è molto robusta.

Se il problema è eseguire delle query in determinato orario si può usare l’event scheduler di MySQL, ovviamente questo ti costringe ad usare MySQL

Puoi usare una tabella in cui registrare l’orario di esecuzione quindi, ogni minuto o quando è necessario, eseguire le query in ordine. Ho usato questo pattern per un browser game che doveva garantire un minimo di realtime. Se parti dall’idea che una query non deve essere eseguita in un dato istante, ma deve garantire lo stesso risultato che eseguirebbe in quell’istante, … puoi fare cose molto interessanti ed addirittura ottimizzare il carico di lavoro sul database.

… allora … lato SQL è tutto ok … è tutto fatto bene ed ottimizzato, tant’è che riusciamo ad autobilanciare il carico, etc, etc… etc…

quello che chiedevo è una info tecnica su come rendere un yiic command molto simile ad un demone

Non credo che php sia la soluzione giusta per fare questo. Potresti usare esattamente un demone che sta sempre attivo in background e fa chiamate get o post alla tua applicazione yii.

Se proprio vuoi scrivere un demone in php Questo ti sarà utile, se non fondamentale :)

Anche se, secondo me, un demone deve essere scritto per benino e in un linguaggio più di basso livello.

Aggiungo un piccolo tutorial che ho trovato che pare interessante!