Questo è un post che non dovrei scrivere. La convenzione nel settore è celebrare i successi, mostrare case study patinati, tacere sui fallimenti. Io faccio il contrario, e la ragione è semplice: quasi tutto quello che ho imparato di utile sulle automazioni AI in produzione l’ho imparato dai fallimenti, miei o di altri. Nascondere i fallimenti ai clienti futuri significa farli ripetere a loro spese.
Il 13 aprile 2026 abbiamo fatto il primo test end-to-end completo della pipeline AI iaFlux per un cliente moda italiana. L’architettura era già progettata, testata in unita, smoke-tested. Dieci foto in coda, aspettativa: dieci foto processate con successo. Risultato del primo run: 60 record di errore nel database, 6 job bloccati in stati intermedi, 3 bug critici distinti attivi contemporaneamente. Recovery totale richiesto. Pipeline resettata e ripartita.
Dopo i fix: 10 foto su 10 processate correttamente, costo totale $0,19, classificazione 100% OK. Ma il primo run è stato un disastro istruttivo. Questo è cosa è andato storto, come l’abbiamo diagnosticato, cosa abbiamo fixato, e le sei lezioni che applico oggi a ogni automazione in produzione. Se vuoi il contesto positivo completo, il case study con i numeri finali del batch è pubblicato come post separato.
Il contesto — pipeline AI per 126 foto e-commerce
Per chi non conosce il caso: il cliente è un’azienda moda italiana con 126 foto prodotto da allineare (rimozione sfondo, normalizzazione colore, ritaglio coerente). La pipeline iaFlux usa tre workflow n8n che parlano con Supabase Postgres come job queue, Flux Kontext Pro su Replicate come modello AI, Google Drive come storage input/output. Lo stack tecnico completo, con costi mensili reali è descritto nel post dedicato.
La scelta dell’orchestratore non è neutra rispetto a questi errori: per capire perché abbiamo costruito su n8n e quando conviene un’alternativa, abbiamo scritto un confronto tra n8n, Make e Zapier.
L’architettura era disegnata bene sulla carta:
- Workflow 1 (Ingestion) scansiona INBOX ogni 60 secondi, accoda i nuovi file in Supabase
- Workflow 2 (Worker) gira ogni 10 secondi, processa il prossimo job in coda con lock esplicito
- Workflow 3 (StuckRecovery) gira ogni 60 secondi, riaccoda job bloccati da lock scaduto
- Budget check, retry con classificazione errori, dead letter queue dopo 3 tentativi
Ogni componente testato in unita. Smoke test passato con 2 foto. Demo al cliente approvata. Si accende in produzione con 10 foto reali e iniziano i problemi.
Primo sintomo — errori generici di Replicate
Dopo 15 minuti dal go-live, il log errori di Supabase inizia a riempirsi. Errori generici tipo “bad request”, “invalid image format”, “prediction failed”. I job venivano ritentati e falliti, ritentati e falliti. Il contatore retry_count saliva a 3 e i job finivano in dead_letter.
Prima diagnosi sbagliata: “Replicate ha problemi momentanei, aspettiamo”. Seconda diagnosi sbagliata: “forse il modello Flux Kontext Pro ha rate limit non documentati”. Queste diagnosi sbagliate hanno fatto perdere 40 minuti di tempo reale di debug. Vero errore: non guardare il payload effettivo che stavamo mandando all’API.
Quando siamo finalmente andati a vedere cosa stavamo inviando a Replicate, la sorpresa: l’URL dell’immagine non era un file binario, era una pagina HTML di Google Drive. Questo ci porta al primo bug critico.
Bug P0 — URL Drive non compatibile con Replicate
Severita: Critica (blocca completamente la pipeline).
Scoperta: Dopo 40 minuti di diagnosi sbagliata.
Sintomo: Replicate risponde con errori generici invece di processare l’immagine.
Il workflow di ingestion rendeva i file su Drive pubblici e generava URL del tipo https://drive.google.com/uc?export=download&id=FILE_ID. Questo URL, per file sotto i 5MB, restituisce effettivamente il binario dell’immagine. Per file sopra i 5MB — come le nostre foto da 8192×5464 pixel che pesano 20-40MB — Google Drive non restituisce il file direttamente. Restituisce una pagina HTML di conferma virus-scan con un link “Download anyway”.
Replicate vedeva l’URL, faceva una GET, riceveva HTML invece di bytes di immagine, provava a interpretare l’HTML come immagine, e falliva con un errore generico “invalid image format”. Nessun indizio dal messaggio che il problema era HTML-vs-binary.
Fix applicato: invece di passare URL Drive, scarichiamo il file all’interno del container n8n via OAuth2 (autenticazione Google), poi facciamo upload multipart a Replicate Files API (POST https://api.replicate.com/v1/files). Replicate restituisce un proprio URL temporaneo (scade in 24 ore) che garantiamo contenga il binario corretto. Zero ambiguita, zero pagine HTML di mezzo.
Costo del fix: 2 ore di lavoro, 0 costi aggiuntivi. Replicate Files API è gratuita.
Lezione: ogni interfaccia tra due sistemi è un potenziale punto di rottura. Non dare mai per scontato che un URL “funzioni” senza verificare cosa restituisce veramente quell’URL al fornitore di servizio. Il problema non erano ne Google Drive ne Replicate: erano le assunzioni implicite tra i due.
Bug P1 — Retry infinito su errore 402 crediti esauriti
Severita: Alta (può bruciare budget).
Scoperta: Accidentale, mentre sistemavamo P0.
Sintomo: Un job che ha fallito una volta per crediti esauriti viene ritentato all’infinito.
Il nostro error classifier guardava il codice HTTP di risposta e decideva se l’errore era temporary (retry automatico dopo N secondi) o permanent (job marcato come fallito, no retry). Codici 5xx erano temporary, codice 4xx erano permanent. Logica standard.
Il problema: HTTP 402 (Payment Required) — usato da Replicate quando il credito è esaurito — era classificato come temporary per default. Risultato: un job che aveva fallito una volta per crediti zero veniva rischedulato ogni 30 secondi, finendo sempre nello stesso errore 402. Il contatore retry_count saliva a 3 e poi si fermava, ma solo dopo aver tentato 3 volte ogni job della coda. Con 10 job in coda e 3 retry ciascuno, sono 30 tentativi inutili su un account a credito zero.
Il danno in questo caso è stato minimo perche eravamo a credito zero, quindi ogni retry falliva senza consumare nulla. Ma in uno scenario reale con credito ridotto (non zero), il bug avrebbe sparato decine o centinaia di retry validi consumando dollari in errori inutili. In uno scenario worst case con bug di consumo anomalo su Replicate (es. prompt più lungo del normale), un loop di retry può generare fatture da migliaia di dollari in poche ore. Il tema del costo AI subdolo e variabile che sfugge di mano è trattato come limite numero 4 nel post dedicato.
Fix applicato: check esplicito if (response.status === 402) errClass = 'permanent'. Il job finisce immediatamente in failed senza retry e il worker invia un alert via email.
Fix architetturale aggiunto: budget_check come primo nodo del worker. Prima di ogni esecuzione, il worker interroga l’endpoint Replicate /account e verifica il credito disponibile. Se sotto soglia di sicurezza (configurabile, default 5 dollari), il worker esce immediatamente senza tentare il job. Questo preveniene anche il caso di retry su account non ancora ricaricato.
Lezione: ogni pipeline AI in produzione deve avere due meccanismi anti-runaway di default. Budget check preventivo (prima di ogni esecuzione) e budget cap massimo giornaliero (sopra X dollari in un giorno, tutto si ferma). Se il tuo fornitore non te li ha inclusi, te li stai prendendo addosso al primo incidente serio.
Bug P2 — Trigger 10s causava concorrenza distruttiva
Severita: Media (degrada le performance ma non blocca).
Scoperta: Correlando timing esecuzioni con picchi di errori.
Sintomo: Errori intermittenti “Try spacing your requests out”.
Il trigger del workflow worker era impostato ogni 10 secondi. L’idea era processare la coda velocemente. Dettaglio ignorato: ogni singolo job richiede circa 25-30 secondi end-to-end (download, upload Replicate, prediction, polling, QC, upload output, finalize).
Cosa succedeva con trigger 10s e job 25-30s: la seconda esecuzione del worker partiva prima che la prima fosse finita, la terza prima che la seconda, la quarta prima che la terza. Tre esecuzioni in parallelo che facevano lock sul database, HTTP request concorrenti su Replicate, scritture simultanee su Drive.
n8n ha un meccanismo interno di throttling per prevenire abuso sulle API esterne. Quando vede troppe richieste HTTP simultanee partire dallo stesso nodo, inizia a buffer-arle e poi a rifiutarle con l’errore “Try spacing your requests out”. Non è un limite di Replicate o Google, è n8n che si auto-protegge (e protegge le API esterne dal tuo workflow rumoroso).
L’errore di throttling si propagava come fallimento del job, che tornava in coda, che veniva ritentato, aumentando ulteriormente la pressione. Circolo vizioso di auto-rinforzo.
Fix applicato: trigger del worker portato a 30 secondi. Adesso ogni esecuzione ha il tempo di finire prima che parta la successiva. Zero concorrenza, zero throttling. Pipeline più lenta in termini di throughput teorico (120 job/ora invece di 360), ma stabile.
Per aumentare il throughput senza reintrodurre concorrenza distruttiva, abbiamo aggiunto la possibilita di eseguire più worker in parallelo (ciascuno con il proprio workflow trigger 30s) usando il pattern SKIP LOCKED di Postgres per evitare race condition sui job.
Lezione: il trigger interval deve essere sempre almeno 20-30% più lungo del tempo di esecuzione medio di un singolo job. Se vuoi throughput maggiore, la soluzione è parallelizzare con più worker, non triggerare più spesso lo stesso worker. Trigger frequenti su esecuzioni lente = concorrenza distruttiva garantita.
Il recovery — come resettare una pipeline in stato caotico
Dopo aver individuato i tre bug, la pipeline era ancora in uno stato sporco: 60 record di errore nel log, 10 job in vari stati intermedi (processing, polling, dead_letter), 6 lock orfani che non si liberavano, contatori di retry saturi.
Applicare i fix senza resettare lo stato avrebbe significato continuare a processare su un backlog di errori già esistenti. Servivano tre operazioni chirurgiche sul database Supabase:
- Clean del log errori:
TRUNCATE iaflux.error_logper partire pulito. Gli errori storici erano tutti riferiti ai bug fixati, tenerli avrebbe inquinato le statistiche future. - Reset dei job bloccati:
UPDATE iaflux.jobs SET status='queued', retry_count=0, prediction_id=NULL, worker_id=NULL, classification=NULL, lock_acquired_at=NULL, lock_expires_at=NULL, error_type=NULL, error_message=NULL WHERE status NOT IN ('success'). Tutti i job che non erano stati completati con successo vengono resettati come nuovi. - Azzeramento cost log:
TRUNCATE iaflux.cost_logperche i costi registrati erano tutti riferiti a tentativi falliti, non a reali elaborazioni.
Dopo queste tre query, abbiamo rilanciato la pipeline. Stavolta con i fix applicati, trigger a 30 secondi, budget check attivo, URL Replicate corretti. Risultato del secondo run: 10 job su 10 processati correttamente, costo totale $0,1884, classificazione 100% OK, tempo reale 90 minuti (incluso il throttling naturale di Replicate su prediction consecutive).
Il recovery ha richiesto 15 minuti di lavoro. Il debug che ci ha portato a capire i tre bug ha richiesto 3 ore di lavoro. Lezione collaterale: saper recuperare una pipeline bloccata in stati intermedi è un’abilita separata da saperla progettare. Va esercitata prima di metterla in produzione, non durante il primo incidente.
Le 6 lezioni distillate
Dopo questa esperienza, ho consolidato sei lezioni che applico a ogni pipeline AI in produzione. Non sono consigli generici di manualistica. Sono cicatrici operative.
1. Ogni integrazione tra due sistemi va verificata con il payload reale
“L’ho configurato, dovrebbe funzionare” è la frase che precede ogni disastro. Prima di mettere una pipeline in produzione, intercetta il payload esatto che invii al sistema esterno e verifica che sia quello che il sistema si aspetta. Per Replicate: intercetta l’URL che gli passi e fai una curl -I da locale per vedere cosa restituisce. Per API di gestionali: genera un payload finto e mandalo a mano con Postman prima di automatizzare.
2. Classificare gli errori è più importante che loggare gli errori
Loggare ogni errore è facile e non serve a niente. Classificare gli errori in categorie azionabili (temporary, permanent, budget_exhausted, rate_limited, auth_failed) è difficile ed è il 70% del valore di un sistema robusto. Ogni categoria ha una strategia di reazione diversa: retry, dead letter, alert critico, disattivazione del worker. Senza classificazione, un sistema di retry è un moltiplicatore di problemi, non una soluzione.
3. Ogni pipeline AI deve avere budget check preventivo
Non negoziabile. Prima di ogni esecuzione: verifica il credito disponibile sull’API AI e non partire se è sotto soglia. Questo previene il caso di retry su account a credito zero e — più importante — il caso di bug di consumo anomalo che brucia centinaia di dollari in poche ore. Costo implementativo: 30 minuti. Costo del non implementarlo: potenzialmente illimitato.
4. Il trigger interval deve essere sempre più lungo del tempo di esecuzione
Regola empirica: trigger interval = tempo medio di esecuzione + 30% di margine. Se un singolo job impiega 25 secondi, trigger minimo 33 secondi (arrotondato a 30-45 secondi). Per throughput maggiore, parallelizzare con più worker con pattern SKIP LOCKED. Mai aumentare la frequenza di trigger sullo stesso worker sperando in più throughput: ottieni solo concorrenza distruttiva.
5. I lock distribuiti devono avere sempre un timeout e un recovery
Un lock senza timeout è un deadlock in attesa di accadere. Ogni lock in una pipeline (sia esso in Postgres, Redis, o un semaforo applicativo) deve avere un timeout esplicito (tipicamente 2-3x il tempo di esecuzione massimo atteso) e un recovery automatico per i lock scaduti. Senza recovery, il primo crash di un worker lascia un lock orfano che blocca tutto finché qualcuno non lo pulisce a mano.
6. Il recovery da stato caotico va esercitato prima, non durante l’incidente
Quando la pipeline è bloccata e ci sono 60 record di errore nel log, non è il momento di imparare quali query SQL di reset sono sicure e quali no. Scrivi le query di recovery in anticipo, testale su un backup del database di produzione, documentale come procedura operativa. Un bug critico trovato in produzione si recupera in 15 minuti se sai cosa fare, in 4 ore se lo stai scoprendo sotto pressione.
Cosa porterai via da questo post
Il messaggio più importante non è tecnico: è che ogni pipeline AI in produzione avra incidenti nei primi 30-60 giorni. Non è una possibilita, è una certezza. L’AI introduce componenti distribuiti nuovi (API esterne con latenza variabile, modelli che consumano risorse in modo non lineare, rate limit nascosti) che creano classi di errori mai viste prima.
La differenza tra una pipeline che sopravvive e una che fallisce non è il codice iniziale. È la capacita di osservare, diagnosticare e recuperare quando le cose vanno storte. Pipeline senza logging strutturato, senza classificazione errori, senza budget check, senza recovery automatico non sono pipeline: sono esperimenti che qualcuno ha messo in produzione troppo presto.
Se stai pianificando un progetto AI per la tua PMI, chiedi al fornitore quali meccanismi di recovery e monitoraggio ha previsto prima ancora di chiedere quale modello AI userà. Se non ha una risposta pronta, cerca un altro fornitore.
Domande frequenti
Cosa succede se un’automazione si blocca in produzione?
Una pipeline ben progettata ha un meccanismo di recovery automatico (come WF3 StuckRecovery in iaFlux): i job bloccati vengono rilevati dopo un timeout (tipicamente 10 minuti), il lock viene rilasciato e il job viene rimesso in coda automaticamente. Senza recovery automatico, i job rimangono in stati intermedi (claimed, processing, polling) finche qualcuno non li resetta manualmente con query SQL. Questo può trasformare un blip di 2 minuti in un blocco di ore se nessuno è di guardia al sistema.
Come si gestisce il budget AI in un’automazione in produzione?
Il modo più sicuro è implementare due meccanismi combinati. Primo: un budget_check come primo step di ogni esecuzione del worker che verifica i crediti disponibili sull’account AI prima di processare qualsiasi job. Se il credito è sotto soglia di sicurezza (tipicamente 5-10 dollari), il worker si ferma e invia un alert. Secondo: un budget cap giornaliero hard-coded nel sistema che disattiva automaticamente il worker se la spesa supera una soglia configurata (es. 50 dollari/giorno). Questi due meccanismi insieme prevengono sia il caso retry-infinito su account esaurito sia il caso bug-di-consumo-anomalo.
Quante esecuzioni concorrenti può gestire n8n su un VPS standard?
n8n su Docker su VPS 2 vCPU / 4GB RAM gestisce senza problemi 3-5 esecuzioni concorrenti per workflow. Il limite non è tipicamente la CPU ma la contesa sui lock del database (SQLite o Postgres) e il throttling HTTP interno di n8n che protegge le API esterne. Per volumi PMI tipici (1.000-10.000 operazioni al giorno) un singolo VPS è sufficiente. Per volumi superiori si parallelizzano più worker o si scala verticalmente a 4 vCPU/8GB. Il trigger interval minimo consigliato è 30 secondi per workflow con esecuzioni sopra i 20 secondi.
Quanto tempo prima che un’automazione AI funzioni davvero senza problemi?
I primi 30-60 giorni di produzione sono statisticamente i più problematici: si scoprono bug di integrazione, edge case non previsti, limiti API non documentati. Dopo 60-90 giorni di produzione con monitoring attivo e iterazioni, la pipeline tipicamente stabilizza a un tasso di errore sotto l’1%. Continua ad esserci sempre un 0,5-1% di errori transitori che il recovery automatico gestisce senza intervento umano. La pipeline iaFlux per il cliente è stabile dal secondo run post-fix (aprile 2026) con zero interventi manuali necessari fuori dalla manutenzione ordinaria.
Parliamone.
Se hai in mente un progetto di automazione AI e vuoi discutere con chi ha già attraversato questi errori al posto tuo, l’audit iniziale è gratuito e dura 30 minuti. Ti facciamo una mappa dei rischi specifici del tuo caso e dei meccanismi di protezione che servono fin dal giorno uno. Se stai gia correndo in produzione con problemi simili a quelli descritti qui sopra, lo stesso audit gratuito può trasformarsi in un piano di recovery operativo.
Aggiornato a giugno 2026. Dati riferiti a progetti pilota 2026. Metriche verificabili su richiesta.
Vuoi un sistema così nella tua azienda?
Partiamo da un audit gratuito di 30 minuti, senza impegno: ti diciamo se ha senso e quanto può rendere.
Richiedi l'audit gratuito →
Lascia un commento