Casi Maledetti: Diari di un’Infrastruttura eCommerce

Tre storie reali di bug invisibili, perdite finanziarie silenziose e ingegneria deterministica nel backend operativo.


1. Il bug invisibile di WooCommerce: quando i webhook smettono di parlare (e come evitarlo)

Lunedì mattina, ore 11:30. Il reparto logistico telefona in amministrazione: “Come mai oggi non ci sono ordini da preparare? È tutto fermo da stamattina”.
L’eCommerce Manager apre la dashboard dello store WooCommerce: 23 ordini ricevuti e pagati regolarmente nelle ultime tre ore. Eppure, sul gestionale l’elenco è vuoto. Nessun server è caduto, non ci sono errori nei log di sistema, la CPU è al 5% e il database risponde in millisecondi. Tutto sembra apparentemente normale.

Questo è il guasto silenzioso classico delle integrazioni WooCommerce trascurate.

La Causa: La disattivazione silenziosa di WooCommerce

Quando un ordine viene completato, WooCommerce invia una notifica HTTPS (webhook) al sistema di destinazione. Se il server dell’ERP o della logistica ha un micro-ritardo temporaneo (ad esempio un timeout di rete di 5 secondi dovuto a un sovraccarico momentaneo), la chiamata fallisce.
WooCommerce riprova a consegnare il webhook. Se riscontra pochi fallimenti consecutivi, attiva una funzione nativa devastante: imposta lo stato del webhook su “disabled” nel database, in silenzio, senza avvisare nessuno.

Da quel secondo in poi, l’integrazione smette di funzionare. Il merchant lavora alla cieca finché un magazziniere non si accorge del vuoto anomalo sulle linee di spedizione.

La Soluzione: Riconciliazione asincrona + Watchdog attivo

Un’integrazione professionale non si basa sulla speranza che la rete e i webhook funzionino sempre. Si progetta partendo dal presupposto che prima o poi falliranno.

Per risolvere questo problema alla radice, la nostra infrastruttura PHABDEV applica tre livelli di sicurezza:

  1. Il Poller di Sicurezza: Accanto al webhook in tempo reale, facciamo girare un processo di polling periodico controllato da un cursore temporale (WOO_LOOKBACK_MIN). Se il webhook salta, il poller recupera l’ordine mancante al ciclo successivo.
  2. La query corretta su modified_after: Molti sviluppatori usano il parametro after (data di creazione dell’ordine) per interrogare le API di WooCommerce. Questo è un errore grave: se un ordine nasce in stato “pending” (non pagato) e viene pagato dopo tre ore, il poller con filtro sulla data di creazione lo salterà per sempre. Usiamo rigorosamente modified_after, così ogni cambio di stato riporta l’ordine nel mirino della sincronizzazione.
  3. Il Watchdog delle API: Un monitor interno controlla ogni minuto il timestamp dell’ultimo ciclo riuscito di ciascun poller (ultimoOkMs) e lo stato del webhook WooCommerce. Se il webhook passa da active a qualsiasi altro stato, il Watchdog notifica immediatamente il team tecnico su Telegram, indicando la scheda di ripristino del Runbook prima che il cliente finale o la logistica avvertano il disservizio.

2. GID vs ID: Come Shopify ha quasi sdoppiato la contabilità di un merchant

Nel collaudo end-to-end di una nuova integrazione custom per un importante merchant Shopify, l’ordine di test #1003 è apparso due volte nell’anagrafica del gestionale aziendale. Due righe identiche, due fatture emesse con protocolli consecutivi, magazzino scalato del doppio rispetto alla merce realmente venduta.

L’integrazione possedeva un registro di idempotenza robusto per impedire le doppie scritture. Eppure, la barriera di sicurezza era stata aggirata.

La Causa: Il doppio formato degli identificativi di Shopify

Andando a ispezionare i log dei payload in ingresso, abbiamo scoperto l’origine del conflitto. L’architettura utilizzava due vie di ricezione per garantire l’alta affidabilità: i webhook in tempo reale (REST) e un poller GraphQL Admin API per la riconciliazione notturna.

  • Il webhook REST trasmetteva l’identificativo dell’ordine come stringa numerica classica: "1003".
  • Il poller GraphQL rispondeva usando il formato globale di Shopify (GID): "gid://shopify/Order/1003".

Per la pipeline di ricezione naive, si trattava di due entità distinte. Il registro di idempotenza ha creato due chiavi differenti nel database e ha fatto passare l’ordine due volte, sdoppiando la transazione contabile.

La Soluzione: Normalizzazione stringente al confine dell’adapter

La Clean Architecture impone una regola ferrea: le differenze specifiche delle piattaforme non devono mai contaminare il nucleo dell’applicazione.

Abbiamo risolto estraendo la logica di normalizzazione degli ID all’estremo confine dell’adapter Shopify, prima che l’ordine venga convertito nel modello canonico interno:

export function shopifyOrderExternalId(rawId: string): string {
  if (rawId.startsWith('gid://')) {
    const parti = rawId.split('/');
    return parti[parti.length - 1];
  }
  return rawId;
}

Che arrivi un GID GraphQL o un intero REST, l’adapter lo normalizza in un’unica stringa numerica pura. Il nucleo del middleware riceve esclusivamente l’ID pulito, garantendo l’idempotenza assoluta.

Inoltre, abbiamo implementato un guardrail logico essenziale: la chiave di idempotenza viene registrata sul database persistente solo dopo che la riserva di magazzino è andata a buon fine. Se un ordine viene rifiutato a monte per stock insufficiente, la chiave non viene bruciata. Questo permette all’ordine di essere riconsegnato e accettato automaticamente non appena lo stock viene rifornito, senza essere erroneamente scartato come duplicato.


3. La trappola del magazzino condiviso: quando lo SKU ripetuto genera oversell

Un merchant che vende abbigliamento di fascia alta su più canali (eCommerce proprietario, Amazon e Zalando) si ritrova improvvisamente con una giacenza negativa sul gestionale. Ha venduto due volte l’ultima felpa taglia L rimasta a scaffale. Entrambi i clienti hanno pagato e si aspettano la consegna il giorno successivo. Uno dei due ordini dovrà essere annullato manualmente, con conseguente danno d’immagine e recensione negativa.

La sincronizzazione stock era attiva ogni 15 minuti. Come è stato possibile l’oversell?

La Causa: Il controllo di giacenza sequenziale (naive)

Il payload arrivato dal marketplace presentava un’anomalia strutturale: lo stesso identico articolo (stesso SKU) era presente su due righe d’ordine distinte (ad esempio, per via di una promozione speciale e di un acquisto standard accorpati dal carrello del cliente).

Il sistema di controllo stock naive dell’eCommerce scorreva le righe dell’ordine una alla volta ed eseguiva la verifica:

  1. Riga 1: Richiesto 1 pezzo dello SKU NRD-TSH-01. Stock disponibile: 1. Esito: Disponibile (accettato).
  2. Riga 2: Richiesto 1 pezzo dello SKU NRD-TSH-01. Stock disponibile: 1. Esito: Disponibile (accettato).

Il codice valutava la disponibilità riga per riga senza aggiornare lo stato temporaneo in memoria prima del commit finale dell’ordine. Ha fatto passare un ordine che richiedeva 2 pezzi totali a fronte di 1 solo pezzo realmente disponibile, mandando il magazzino in negativo.

La Soluzione: Aggregazione preventiva e riserva atomica “Tutto o Niente”

La nostra pipeline d’integrazione previene questa collisione aggregando preventivamente il fabbisogno per SKU prima di interrogare il magazzino, trattando l’intera riserva come una transazione atomica (“tutto o niente”):

// Sotto-carrello aggregato in memoria prima della riserva stock
const fabbisogno = nuoveRighe.reduce((acc, riga) => {
  acc[riga.sku] = (acc[riga.sku] || 0) + riga.qty;
  return acc;
}, {} as Record<string, number>);

La funzione di riserva valuta lo stock sull’intero fabbisogno aggregato dell’ordine (2 pezzi richiesti a fronte di 1 disponibile). Se anche una sola riga o un solo articolo aggregato supera la disponibilità reale, l’intero ordine viene bloccato sollevando un InsufficientStockError ed emettendo un evento stock.rejected nel feed della dashboard.

L’ordine viene respinto in totale sicurezza prima che possa corrompere i dati contabili o generare spedizioni fantasma. Questa è ingegneria dei flussi, non copia manuale dei dati.


Da dove partire per mettere in ordine l’infrastruttura

PHABDEV lavora proprio su questo livello operativo degli eCommerce, con integrazioni tra shop e gestionale, automazioni del backoffice e portali B2B su misura. È una scelta sensata quando il problema non è la singola schermata, ma il flusso completo dei dati.

Se vuoi partire da un controllo concreto, puoi usare la valutazione online dell’eCommerce su questo percorso guidato, con ventotto domande su sette aree operative, un tempo di compilazione di cinque minuti e un punteggio dettagliato per area. Se il tema ti tocca da vicino, puoi anche vedere come lavoro su PHABDEV, perché qui la differenza non la fa il software in vetrina, ma lo strato che tiene in piedi ordini, magazzino e gestionale ogni giorno.

Lascia una risposta

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *