Vai al contenuto
AutoValue
17 ottobre 2026 · Data Quality

La settimana in cui abbiamo quasi perso 84.000 inserzioni per un bug di cui avevamo incolpato i proxy

AutoValue Editorial
La settimana in cui abbiamo quasi perso 84.000 inserzioni per un bug di cui avevamo incolpato i proxy

14 settembre

Aspettavamo questo giorno da settimane. Il nostro fornitore di proxy residenziali era andato in tilt per un problema di fatturazione a luglio, e per due mesi una fetta crescente delle nostre 1.375 fonti aveva scansionato in modo degradato o non aveva scansionato affatto — fetch che andavano in timeout, IP bloccati a metà sessione, il classico lento stillicidio che non si manifesta come un'interruzione quanto piuttosto come un numero che si rimpicciolisce senza che nessuno se ne accorga finché non diventa imbarazzante. Abbiamo rinnovato. Nuovo pool, 20.000 linee di sessione residenziali rotanti, ogni exit testato prima di farlo avvicinare alla produzione. Il 100% del probe è passato. AE, DE, JP — tutti attivi, tutti puliti.

Così abbiamo lanciato una scansione supervisionata, del tipo in cui qualcuno guarda davvero la dashboard invece di fidarsi del cron. Mi aspettavo l'opposto di un disastro.

Quello che abbiamo ottenuto è stato un database che aveva perso 84.401 righe in un solo passaggio, con 102 fonti scese di più del 25% rispetto allo snapshot precedente. Peggio dei due mesi di carestia di proxy che avevamo appena risolto.

La teoria sbagliata, in breve

Il mio primo istinto — e questo lo ammetto senza giri di parole — è stato pensare che il nuovo pool fosse in qualche modo peggiore di quanto suggerisse il probe. Forse gli IP di sessione venivano rate-limitati a metà scansione in un modo che un probe singolo non avrebbe colto. È una teoria ragionevole. È anche sbagliata, e crederci anche solo per mezza giornata ci ha costato un tempo che non avevamo, perché il cron di scansione resta in pausa per tutto il tempo in cui si sta verificando una teoria del genere — non si vuole che un passaggio andato male sovrascriva uno snapshot buono mentre si sta ancora tirando a indovinare.

L'indizio che ha smontato la teoria è stato dubizzle. Una delle nostre fonti a più alto volume negli Emirati, durante quella sessione aveva effettivamente recuperato 32.595 inserzioni — un numero perfettamente sano, i proxy funzionavano chiaramente — e poi le aveva scartate quasi tutte. Non un fetch fallito. Recuperate, e poi buttate via.

16 settembre: trovare il bug vero

È lì che la storia ha smesso di riguardare i proxy ed è diventata una storia di sostituzione delle righe. Il nostro livello di persistenza fa lo snapshot di ogni fonte come una sovrascrittura completa di <site>_cars_for_sale.csv a ogni passaggio — solo le inserzioni attuali, si sostituisce l'intera tabella. È un comportamento corretto quando una scansione finisce. È catastrofico quando una scansione va in timeout a metà strada e lo scraper scrive il batch parziale che è riuscito a raccogliere come se fosse lo snapshot completo. Una fonte che normalmente contiene 9.000 inserzioni attive viene sovrascritta con le 1.200 che ha scansionato prima che scadesse il tempo, e le altre 7.800 svaniscono — non perché le auto siano state vendute, ma perché il nostro stesso codice ha deciso che un fetch incompleto fosse un fetch completo.

I proxy non ci stavano mentendo. Il problema era la logica di retry, ed era silenziosamente malfunzionante da tempo, semplicemente mascherata da un pool più sano che di solito completava i fetch prima che lo sweep diventasse un problema.

Ecco cosa ci è costato davvero quello sweep, una volta fatti i conti:

Vecchio sweep di retrySweep corretto
Retry per proxy31
Ritardo per tentativo1s—
Tetto effettivo su un pool di 50 proxy~56 minuti per URLbudget totale di 120 secondi
Comportamento in caso di timeoutscrive il batch parziale come snapshot completofonte saltata, mantenuto lo snapshot precedente

Cinquantasei minuti per rinunciare a un singolo URL. Moltiplicate questo su una scansione che tocca oltre mille fonti e ottenete esattamente il tipo di fallimento silenzioso e distribuito in modo irregolare che abbiamo visto — alcune fonti a posto, 102 di esse svuotate, niente nei log che gridasse "interruzione dei proxy" perché, tecnicamente, non ce n'era stata una.

25 settembre: la correzione, e la parte che conta per voi

La patch distribuita nove giorni dopo ha fatto due cose poco appariscenti. Ha limitato la matematica del retry così che un fetch bloccato fallisce rapidamente invece di consumare quasi un'ora, e — questa è quella che effettivamente previene la perdita di dati — un fetch parziale non sostituisce più l'intero set di righe. Se una fonte riesce a completare solo 1.200 delle sue solite 9.000 inserzioni, manteniamo lo snapshot completo precedente invece di sovrascriverlo con una frazione. Lo stesso giorno è arrivata una seconda modifica che scrive un flag CRAWL_PAUSED visibile che il nostro monitoraggio controlla prima di avvisare chiunque di un calo — così una pausa deliberata viene letta come una pausa, non come un allarme.

Perché a un lettore che sta cercando una Hyundai usata dovrebbe importare tutto questo? Perché i contrassegni di sottoprezzo che pubblichiamo — 12.823 attivi sul sito questa settimana — sono onesti solo se la coorte con cui confrontiamo un'inserzione è il mercato regionale reale e completo e non un frammento troncato da un timeout. Un badge di affare costruito su uno snapshot che ha perso tre quarti del suo set di confronto non è un badge di affare, è rumore con un'etichetta verde addosso. Preferiamo sospendere una scansione per nove giorni piuttosto che pubblicare quello.

Il dataset oggi conta 1.108.535 inserzioni in 73 regioni e 1.375 fonti — più grande di prima che iniziasse tutto questo, proxy rinnovati e bug della sostituzione delle righe risolto. Ma il numero a cui continuo a tornare non è il totale. È 84.401 — la differenza tra una scansione che sembrava sana a livello di proxy e una che lo era davvero.

Data QualityWEB ScrapingCrawl ReliabilityBelow Market Deals
Condividi

Articoli correlati