En el desenvolupament d'arquitectures cloud, sovint ens trobem amb incidents que semblen desafiar la lògica. Un dels casos més instructius va ocórrer en una plataforma SaaS multi-tenant que va perdre 41.000 notificacions sense deixar rastre aparent. Analitzem què va passar i quines lliçons podem extreure per dissenyar sistemes més robusts.
L'escenari és el següent: una plataforma envia totes les seves notificacions en segon pla (email, SMS, webhooks) a través d'una cua SQS estàndard. Una funció Lambda consumeix els missatges mitjançant un mapeig d'origen d'esdeveniments. L'equip va configurar correctament una cua de missatges fallits (DLQ) amb maxReceiveCount de 5 i una alarma sobre la profunditat de la DLQ. Tot semblava en ordre.
El divendres a les 6 PM es desplega una actualització de rutina amb dos canvis: primer, l'actualització del SDK del proveïdor d'email que trenca la recerca de credencials; segon, una millora de robustesa que envolta el cos del handler en un try/catch que registra qualsevol excepció i retorna normalment, amb el comentari 'així una notificació dolenta no enverina tot el lot'. El dissabte a les 9 AM l'equip de suport descobreix que cap client va rebre notificacions durant la nit: 41.000 missatges perduts. Les mètriques de CloudWatch no mostren errors de funció, la profunditat de la cua és zero, la DLQ està buida, l'alarma mai va saltar. Tots els panells estan en verd. On van anar a parar els missatges?
Abans de revelar la resposta, avaluem les opcions presentades. L'opció A suggereix que els missatges van creuar un llindar intern de recompte de recepcions i SQS els va eliminar. No existeix tal mecanisme: el recompte de recepcions només dirigeix missatges a una DLQ mitjançant una política de redrive; SQS no elimina mai basant-se en el nombre de recepcions. L'opció C planteja que va expirar el període de retenció de la cua. La retenció per defecte és de 4 dies; els missatges d'unes hores no poden caducar. A més, l'expiració no explicaria un perfil de zero errors i DLQ buida. L'opció D suposa que el desplegament va deshabilitar el mapeig d'origen d'esdeveniments, però una cua no consumida mostraria profunditat creixent. Una cua en zero sense errors indica que els missatges van ser rebuts, 'processats' i eliminats. L'opció B és la correcta: el handler va capturar cada excepció i va retornar èxit; Lambda va reportar una invocació neta, per tant el mapeig d'origen d'esdeveniments va cridar DeleteMessage a cada missatge del lot. Els missatges es van eliminar legítimament, una invocació verda a la vegada.
El problema és conegut com 'swallowing exceptions' o 'excepcions empassades'. En embolicar tot el codi en un try/catch que només registra l'error però no relança l'excepció ni marca el missatge com a fallit, el handler sempre retorna èxit. Lambda interpreta que el processament va ser correcte i elimina els missatges de la cua. La DLQ mai rep res perquè mai se supera el maxReceiveCount; cada missatge es processa una sola vegada (amb èxit des de la perspectiva de Lambda). El registre d'errors en logs queda ocult si no es monitoritzen adequadament; en aquest cas, els logs contenien les excepcions, però ningú els va revisar fins després de l'incident.
Aquest incident subratlla diversos principis de disseny en arquitectures cloud. Primer, la gestió d'errors ha de ser intencional. Un try/catch genèric que silencia fallades és perillós; l'excepció s'ha de propagar perquè el missatge pugui reintentar-se o enviar-se a la DLQ. Segon, la monitorització ha d'incloure no només errors de funció, sinó també mètriques de cua, DLQ i logs no esperats. Tercer, les proves d'integració han de cobrir escenaris de fallada, especialment després de canvis en dependències externes.
A Q2BSTUDIO, com a empresa de desenvolupament de programari i tecnologia, entenem que la fiabilitat en sistemes distribuïts és crítica. La nostra experiència en cloud AWS/Azure ens ha ensenyat a implementar patrons com el de cua de missatges fallits amb reintents controlats, circuit breakers i observabilitat basada en mètriques i alarmes. A més, integrem automatització de processos per garantir que els desplegaments no introdueixin regressions silencioses.
Per evitar aquest tipus de desastres, recomanem les següents bones pràctiques: mai atrapar excepcions sense relançar-les a menys que estigui explícitament justificat; utilitzar un middleware de gestió d'errors a nivell de framework; instrumentar l'aplicació amb mètriques personalitzades (com comptadors d'excepcions); establir alarmes sobre la profunditat de la DLQ i sobre la taxa de missatges eliminats sense error aparent; i realitzar desplegaments progressius amb monitorització en temps real.
El cas també ens recorda la importància de la cultura d'enginyeria: el comentari 'així una notificació dolenta no enverina tot el lot' reflecteix una bona intenció, però mal implementada. La solució correcta per evitar que un missatge problemàtic afecti altres és usar polítiques de batch amb mida reduïda, o bé processar missatges individualment, o implementar un patró de dead-letter per missatge. En Lambda, quan s'usa un lot, si una invocació falla, tots els missatges del lot es reintenten; però si es captura l'excepció i es retorna èxit, es perden tots. L'alternativa és retornar un estat de fallada parcial (per exemple, marcant missatges específics com a fallits en el batch), però això requereix una implementació més curosa.
Aquest incident també té implicacions de negoci: 41.000 notificacions perdudes signifiquen clients insatisfets, pèrdua d'ingressos potencials i dany a la reputació. En entorns SaaS, el lliurament de notificacions és un component crític del producte. Per això, a Q2BSTUDIO integrem sistemes de BI i Power BI per monitoritzar KPIs de lliurament, i fem servir IA per detectar anomalies en patrons de notificacions. A més, la ciberseguretat hi juga un paper: una fallada en l'autenticació de credencials d'email podria exposar dades sensibles si no es gestiona correctament.
La lliçó final és clara: en sistemes asíncrons, la gestió d'errors no és un detall menor; és el cor de la fiabilitat. Mai donis per descomptat que un try/catch genèric és segur. Sempre dissenya amb la DLQ com a xarxa de seguretat i monitoritza activament. I, sobretot, quan introdueixis canvis, no confiïs només que els tests passin; verifica que els camins d'error funcionen com esperes.
A Q2BSTUDIO ajudem empreses a construir aplicacions a mida amb arquitectures cloud robustes. Els nostres equips combinen experiència en AWS, Azure, ciberseguretat, intel·ligència artificial i automatització per evitar incidents com aquest. Si vols que els teus sistemes siguin resilients, contacta'ns.
En resum, la resposta correcta és l'opció B. Els 41.000 missatges es van eliminar perquè cada excepció va ser capturada i el handler va retornar èxit, fent que Lambda cridés DeleteMessage. La cua mai va mostrar errors perquè Lambda va reportar invocacions exitoses. La DLQ va romandre buida perquè cap missatge va ser reintentat. Un cas clàssic d''excepció empassada' que tots els arquitectes cloud han de conèixer.



