Una chiamata di stampa sta in una sola richiesta HTTP, il che fa sembrare la stampa degli ordini l'integrazione più semplice della roadmap. Resta semplice fino alla sera in cui un cliente riceve due scontrini per un ordine, o fino alla sera in cui quaranta ordini non arrivano mai in cucina e nessuno se ne accorge prima della chiusura.
Risposta breve: tre decisioni evitano quasi tutti gli incidenti in produzione. Rispondete al webhook prima di stampare, date a ogni lavoro una chiave stabile perché un doppione sia riconoscibile, e stabilite esplicitamente che cosa succede quando la stampante è offline. Nessuna è difficile, e tutte e tre si aggiungono più facilmente adesso che dopo il primo incidente.
I tre modi di guasto
| Sintomo | Causa reale | Rimedio |
|---|---|---|
| Lo stesso scontrino esce due volte | La piattaforma ha ritentato un webhook lento, o uno stato è stato riapplicato | Una chiave stabile per ordine |
| Ordini mai stampati e nessuno lo sapeva | La stampante era offline e l'errore è stato inghiottito | Una politica offline esplicita più un avviso |
| Il checkout è lento, o va in timeout | La chiamata di stampa gira dentro la richiesta che conferma l'ordine | Rispondere prima, stampare dopo |
I tre sono collegati. Una chiamata di stampa lenta provoca il retry che provoca il doppione, quindi correggere il primo elimina gran parte del secondo.
1. Rispondere al webhook prima di stampare
Shopify, WooCommerce, Stripe e ogni piattaforma seria ritentano quando il vostro endpoint è lento o restituisce un errore. Se il vostro handler stampa in modo sincrono e l'API di stampa impiega due secondi, avete costruito un generatore di retry.
export default async function handler(req, res) {
const order = req.body;
// Confermare subito: la piattaforma smette di ritentare.
res.status(200).end();
// Poi stampare, fuori dalla richiesta che la piattaforma sta aspettando.
await printOrder(order).catch((err) => {
logger.error({ err, orderId: order.id }, 'stampa fallita');
alertOps(order);
});
}
La regola è che il budget di timeout della piattaforma e la latenza della vostra stampante non devono mai condividere una scadenza. È lo stesso motivo per cui i connettori Shopify e WooCommerce non stampano dentro la transazione del webhook.
2. Dare una chiave a ogni lavoro
L'idempotenza qui non è un lusso da sistemi distribuiti. Un ordine può legittimamente innescare il vostro handler più di una volta: un callback del gateway che arriva due volte, un commerciante che riapplica a mano uno stato pagato, un retry del webhook che ha corso contro la vostra conferma.
Mettete un valore stabile in origin, e salvate un flag di stampa dalla vostra parte:
async function printOrder(order) {
const key = `ordine-${order.id}`;
if (await alreadyPrinted(key)) return;
await fetch(`https://www.expedy.fr/api/v2/printers/${PRINTER_UID}/print`, {
method: 'POST',
headers: {
Authorization: `${process.env.API_SID}:${process.env.API_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ printer_msg: buildTicket(order), origin: key }),
});
await markPrinted(key);
}
Due elementi si guadagnano il posto. Il flag locale ferma il doppione prima della rete, e origin rende visibile nello storico di stampa un doppione sfuggito, il che trasforma "mi sa che ha stampato due volte" in una domanda a cui potete rispondere.
Scrivete il flag nella stessa transazione del resto della gestione dell'ordine, se potete. Un flag scritto dopo una chiamata HTTP riuscita lascia una piccola finestra, ed è esattamente da quella finestra che nascono gli scontrini doppi.
3. Scegliere la politica offline di proposito
Chiedetevi che cosa deve succedere quando la stampante resta senza carta, è staccata, o sta dietro un router che si è riavviato. Ci sono solo tre risposte sensate, e quella sbagliata è non scegliere:
- Accodare e consegnare più tardi. Corretto per etichette di spedizione e documenti di magazzino, dove uno scontrino stampato venti minuti dopo serve ancora.
- Ritentare brevemente, poi avvisare. Corretto per le comande di cucina, dove una comanda stampata venti minuti dopo è peggio che inutile perché il servizio è andato avanti.
- Avvisare subito. Corretto quando una persona può agire, e unica opzione che trasforma una perdita silenziosa in un problema noto.
Qualunque scegliate, implementate l'avviso. La differenza tra un fastidio e una brutta serata non è se la stampante si è guastata, è se qualcuno lo ha saputo.
Che cosa non dovreste costruire
I team ricostruiscono di routine meccanismi che l'API già fornisce. Prima di scrivere una coda, uno scheduler e una scala di retry, guardate quali garanzie di consegna avete già: una API push che trattiene il lavoro e lo consegna quando il dispositivo si riconnette rende inutile gran parte di quel codice. Costruite le parti che codificano le vostre regole di business, come quale stampante riceve quale ordine, e lasciate al trasporto l'affidabilità del trasporto.
Provarlo prima della produzione
Tre test intercettano la maggior parte di ciò che arriva in produzione:
- Rigiocate due volte lo stesso webhook. Deve uscire esattamente uno scontrino.
- Staccate la stampante, poi inviate un ordine. La politica scelta deve avvenire in modo visibile, avviso compreso.
- Ordinate un prodotto con un emoji nel nome. Le stampanti termiche parlano ESC/POS; traslitterate prima di inviare, altrimenti lo scoprirete nel momento peggiore. Il riferimento di impaginazione documenta che cosa accetta il formato.
Fateli tutti e tre contro una stampante vera, non un mock. I guasti interessanti sono fisici.
Aprite un account gratuito e collegate i tre test al vostro branch di integrazione prima che ci passi il primo ordine di un cliente.
Da leggere anche: stampare gli ordini Shopify e gli ordini WooCommerce mostrano dove stanno questi agganci in ciascuna piattaforma.
FAQ
Perché lo stesso ordine a volte stampa due volte?
Quasi sempre perché la piattaforma ha ritentato un webhook a cui il vostro endpoint ha risposto lentamente, o perché uno stato pagato è stato applicato più di una volta. Confermate il webhook prima di stampare e date a ogni lavoro una chiave stabile come l'id dell'ordine.
Devo stampare dentro l'handler del webhook?
No. Rispondete 200 subito, poi stampate fuori da quella richiesta. Condividere una scadenza tra il timeout della piattaforma e la latenza della stampante è ciò che genera i retry, e i retry generano i doppioni.
Che cosa deve succedere quando la stampante è offline?
Scegliete una politica di proposito: accodare e consegnare più tardi, ritentare brevemente e poi avvisare, o avvisare subito. La coda si adatta alle etichette di spedizione, l'avviso alle comande di cucina. L'unica risposta sbagliata è non definirla.
Devo costruire una mia coda di stampa?
Di solito no. Una API push che trattiene il lavoro e lo consegna quando il dispositivo si riconnette lo fa già. Scrivete il codice che codifica le vostre regole di business, come l'instradamento verso la stampante, non un secondo livello di trasporto.
Come provo l'affidabilità della stampa prima di andare in produzione?
Rigiocate un webhook due volte aspettandovi un solo scontrino, staccate la stampante e verificate che politica offline e avviso scattino, e ordinate un prodotto con un emoji nel nome. Fateli tutti e tre contro una stampante vera.