Tailored Digital Works webgriffe.com | @webgriffe
Queueing several syncrounous tasks allows us to go further.
Save 30% of the time by queuing index update on product save
Magento CE v. 1.8.1.0 with sample data. Index update on save enabled. Data collected with Xhprof profiler.
Inoltre, il secondo aspetto importante sull'utilizzo di un motore di code, è la possibiltà di ottenere significativi miglioramenti sui tempi di risposta. Ad esempio questi 2 schemi mostrano il salvataggio di un prodotto dal pannello admin fatta sulla stessa installazione Magento in 2 situazioni differenti. In entrambi i casi parliamo di Magento alla versione 1.8.1.0 con i sample data caricati e l'index update on save attivo. Lo schema di sinistra mostra l'operazione su Magento nativo al 100% in cui l'utente clicca sul bottone "Salva", Magento (lato server) comincia ad eseguire le operazioni necessarie ed infine la risposta viene restituita all'utente (che nel frattempo stava "perdendo tempo" aspettando una risposta). Le nostre misurazioni (fatte con Xhprof) ci dicono che tra le operazioni che vengono eseguite lato server, il 30% del tempo viene impiegato dall'operazione di aggiornamento dell'indice per quel prodotto; operazione che non è strettamente necessario sia sincrona. Lo schema di destra invece mostra la stessa operazione su una installazione in cui è stato introdotto un motore di code e una opportuna modifica applicativa. Come prima, l'utente clicca sul bottone "Salva", Magento (lato server) esegue le stesse operazioni di prima ma, quando arriva all'index update, questo task viene passato al motore di code che restituisce immediatamente una risposta a Magento che a sua volta restituisce immediatamente la risposta all'utente. Il tempo di passaggio del compito al motore di code è trascurabile quindi questa situazione permette all'utente di risparmiare il 30% del tempo ogni volta che salva un prodotto. L'operazione di aggiornamento dell'indice per il prodotto salvato verrà poi eseguita da un worker dedicato che, volendo, può anche lavorare su una macchina separata. Vediamo più nel dettaglio come possiamo ottenere questo risultato.The ones we can easly integrate with Magento are:
Defining a Queue Backend (for example Beanstalk)
<?xml version="1.0"?> <!-- app/etc/local.xml --> <config> <global> ... <queue> <backend>beanstalkd</backend> <beanstalkd> <servers> <server> <host>127.0.0.1</host> </server> </servers> </beanstalkd> </queue> ... </global> </config>
Defining a Queue
<?xml version="1.0"?> <!-- app/code/local/MyVendor/MyModule/etc/config.xml --> <config> ... <queues> <queueName> <label>The Queue Name</label> <class>module/queueHandler</class> <workers> <taskName> <class>module/worker</class> <method>methodName</method> </taskName> </workers> </queueName> </queues> ... </config>
Adding tasks to Queue
$_queue = Mage::helper('lilqueue')->getQueue('queueName'); $_task = Mage::helper('lilqueue')->createTask( 'taskName', array('data'=>'to provide', 'to'=>'the worker'), $storeToRunAs ); // Optionally $_task->setPriority(100) ->setDelay(60) ->setTtr(60); $_queue->addTask($_task);
Worker
class My_Module_Model_Worker extends Lilmuckers_Queue_Model_Worker_Abstract { public function methodName(Lilmuckers_Queue_Model_Queue_Task $task) { //get the store assigned with the task $store = $task->getStore(); //get the queue handler for this queue $queue = $task->getQueue(); //get the data assigned with the task $data = $task->getData(); //This task ended properly $task->success(); //this task needs to be repeated $task->retry(); //this task errored and we should drop it from the queue $task->hold(); //this worker is taking a long time, we should extend it $task->touch(); } }
$ php /path/to/magento/shell/queue.php --watch <queues>
Open source code on GitHub github.com/webgriffe/index-queue-extension
Dall'esperienza dell'hackathon è quindi nata una estensione open source (disponibile su GitHub) che delega tutte le operazioni di aggiornamento dell'indice su una singola entità ad un motore di code e permette di ottenere quel miglioramento sui tempi di risposta che abbiamo visto prima. E' una estensione open source e utilizzablie gratuitamente. E' provvista di test automatici e di uno script di continous integration. Sulla pagina GitHub del repository è possibile trovare la documentazione sul suo utilizzo e le istruzioni per contribuire. Vediamola un po' più nel dettaglio.Architecture
L'estensione riscrive l'Indexer model nativo di Magento che viene richiamato ogni volta che sia necessario aggiornare l'indice per una singola entità (metodo processEntityAction). In questo modo, ogni volta che si cerca di aggiornare l'indice per una singola entità l'estensione può delegare l'operazione a Beanstalk (o altro queue manager) attraverso il relativo Adapter e restituire il controllo all'applicazione in tempo quasi 0. Contemporaneamente e su un processo separato sarà in ascolto l'IndexWorker che, sempre tramite l'Adapter, riceverà il task e lo eseguirà andando a richiamare l'Indexer model nativo di Magento; ottenendo così l'aggiornamento dell'indice in modo totalemente asincrono.Tailored Digital Works webgriffe.com | @webgriffe