Magento 2

Magento insights: come migliorare il processo di acquisto con operazioni asincrone

Lettura 5 minuti

Introduzione

Questo articolo illustra come risolvere alcune problematiche di integrazione grazie a specifici accorgimenti nel design dello sviluppo su Magento 2.

A quanti di noi è capitato di avere tempi di risposta elevati, dati dal disservizio di un sistema esterno? E quante volte è capitato durante il processo di acquisto?

In questo articolo vedremo perché è importante disaccoppiare Magento da problemi di latenza o raggiungibilità di servizi esterni nella fase più critica di un ecommerce, il piazzamento di un ordine.

Come un’operazione sincrona può bloccare il processo di acquisto.

PHP nasce come un linguaggio sincrono, ed è forse questo il motivo per cui gran parte dei moduli Magento, che implementano l’integrazione con sistemi esterni, adottano un approccio sincrono alla comunicazione.

Ma in cosa consiste la comunicazione sincrona e quali sono i possibili scenari?

Le comunicazioni sincrone sono caratterizzate da un’applicazione client che invia una richiesta verso un servizio esterno, bloccando la propria esecuzione fino alla ricezione di una risposta o di un timeout.

Pensiamo, ad esempio, alla comunicazione dei dettagli dell’ordine ad un sistema di marketing automation o di raccolta di recensioni. Supponiamo che ci sia un after plugin sul metodo save() dell’entità ordine, per l’invio della chiamata all’API del sistema esterno, cosa potrebbe succedere?

Di seguito i possibili scenari:

  • la chiamata esterna va a buon fine, il tempo richiesto per il piazzamento di un ordine aumenterà in misura direttamente proporzionale al tempo di latenza
  • la chiamata esterna fallisce, anche in questo caso il tempo richiesto sarà proporzionale al tempo di risposta del servizio e non sarà possibile ritentare la chiamata per cercare di recuperare l’errore (sempre che sia un errore recuperabile)
  • il servizio esterno non è raggiungibile, il processo di acquisto sarà bloccato fino al raggiungimento di un timeout che se non gestiamo correttamente, potrebbe dare dei problemi. È importante analizzare come la libreria che stiamo utilizzando gestisce i timeout e agire di conseguenza, non fidiamoci dei valori di default. Ad esempio, la curl in PHP non sovrascrive gran parte delle opzioni relative ai timeout, lasciando alcune di queste impostate a “tempo indefinito” (es. CURLOPT_TIMEOUT e CURLOPT_TIMEOUT_MS).

Come migliorare il processo di acquisto con operazioni asincrone

Le comunicazioni asincrone adottano l’approccio Fire and Forget in cui, l’applicazione client invia la sua richiesta (“fire”) e poi continua la sua elaborazione non aspettando di ricevere il risultato (“forget”) della richiesta inviata.

Una forma di comunicazione asincrona service-to-service è la coda dei messaggi.

Magento supporta RabbitMQ come broker di messaggi e la documentazione ufficiale ne consiglia l’utilizzo per una maggiore scalabilità.

Per adottare un sistema più semplice di gestione dei messaggi, è la stessa documentazione ufficiale ad indicare MySQL come un potenziale sostituto di RabbitMQ, ed è questa la soluzione che potremmo adottare per la nostra integrazione.

Utilizzando MySQL, i messaggi saranno storicizzati in una tabella che potrebbe avere la seguente struttura:

CREATE TABLE `unhealthy_system_order` (
 `id` int(10) NOT NULL AUTO_INCREMENT,
 `order_id` int(10) NOT NULL,
 `order_info` text NOT NULL DEFAULT '',
 `status` varchar(50) NOT NULL DEFAULT '',
 `num_tries` int(11) NOT NULL DEFAULT 0,
 `messages` text NOT NULL DEFAULT '',
 `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
 `processed_at` timestamp DEFAULT NULL,
 PRIMARY KEY (`id`)
)

Utilizziamo, quindi, il nostro after plugin sul metodo save() dell’entità ordine, solo per gestire la persistenza delle informazioni nella tabella unhealthy_system_order. L’invio dei vari ordini sarà processato in un secondo momento tramite un cron job ed impostando in modo adeguato il timeout.

Con un simile approccio disaccoppiamo il salvataggio dell’ordine da eventuali problemi di latenza, fallimento o mancata raggiungibilità del servizio esterno.

Un altro vantaggio che otterremmo è la possibilità di ritentare la chiamata in caso di errore o mancata raggiungibilità, prevedendo un numero massimo di tentativi di esecuzione (tracciabili nella colonna num_tries della nostra tabella).

Ma l’approccio asincrono è sempre la giusta soluzione?

Abbiamo visto i vantaggi delle operazioni asincrone, ma allo stesso tempo il maggior sforzo richiesto per la relativa implementazione.

La risposta è quindi “dipende”.

In un flusso delicato come quello del checkout, è la stessa documentazione ufficiale che indica, tra le best practice, l’implementazione asincrona di alcune operazioni come, l’invio della mail di notifica, il reindex della griglia ordini e l’aggiornamento dello stock.

Vi sono scenari in cui un’operazione sincrona potrebbe essere la scelta migliore per diverse ragioni, vediamone alcune:

  • il risultato deve essere immediatamente riscontrabile dall’utente, come ad esempio, mostrare la disponibilità a magazzino chiamando una API di un ipotetico Warehouse Management System (WMS). In questo caso, la chiamata potrebbe avvenire in maniera totalmente sincrona, effettuando la chiamata server-to-server con timeout ed in caso di errore, sarà mostrato il classico messaggio “al momento non è possibile recuperare l’informazione”
  • l’operazione non ha impatti sul processo di acquisto, si tratta di un servizio esterno affidabile che prevede un allineamento dei dati, nei casi straordinari di mancata raggiungibilità. Un esempio potrebbe essere l’invio di dati verso un servizio di reportistica, dove non è fondamentale l’invio immediato del dato e non è quindi un problema ricorrere ad un successivo allineamento in caso di errore, sempre che si tratti di casistiche straordinarie.

Conclusioni

Implementare operazioni sincrone è sicuramente la soluzione più semplice e veloce, ma allo stesso tempo significa accettare un forte accoppiamento temporale tra i sistemi coinvolti.

Le operazioni asincrone, in determinati contesti, come il processo di acquisto, ci consentono di disaccoppiare Magento da eventuali problemi di latenza o raggiungibilità dei sistemi esterni.

Per i nostri prossimi sviluppi poniamoci la domanda: “E se il servizio non risponde, che problemi posso avere?”, scegliendo di conseguenza l’approccio più adatto e impostando in modo adeguato il timeout.


Crediti: Foto di Adrien Delforge da Unsplash

Articolo scritto da

Back-end dev | Miglianico (CH)