Quan una eina d'auditoria basada en intel·ligència artificial triga diversos minuts a analitzar un contracte intel·ligent, l'usuari no hauria d'haver d'endevinar si el procés encara està viu o s'ha penjat. L'experiència real amb un spinner que no mostra progrés demostra que, passats noranta segons, la majoria d'usuaris refresquen la pàgina i perden la feina ja feta. Aquest problema va portar a redissenyar el flux de comunicació entre el backend i el navegador utilitzant Server-Sent Events (SSE), una tecnologia que encaixa perfectament amb treballs llargs i unidireccionals, però que exigeix un disseny acurat més enllà dels tutorials bàsics.
L'elecció d'SSE davant de WebSockets no és trivial. En un escenari on el client només necessita escoltar després d'enviar una sol·licitud (pujar un contracte i rebre resultats), SSE ofereix justament el que cal: una connexió HTTP persistent del servidor cap al client, reconnexió automàtica mitjançant l'objecte EventSource del navegador, i zero gestió de sockets. WebSockets afegiria complexitat bidireccional que rarament s'aprofita. Per tant, per a treballs llargs d'IA on la comunicació és majoritàriament descendent, SSE és l'opció més lleugera i fiable.
La primera lliçó va ser la importància de dissenyar un vocabulari d'esdeveniments abans d'escriure cap línia de codi. En un primer intent, el backend emetia allò que li semblava: tokens del model, línies de registre, pensaments a mig formar. El frontend es convertia en un parser d'un format no documentat que canviava amb cada modificació del backend. La solució va ser definir una sèrie de tipus d'esdeveniments fixos, tractats com un contracte d'API. Amb quatre tipus n'hi ha prou: progrés, troballa parcial, finalització i error. Cadascun amb una estructura clara: el progrés ha d'indicar passos semàntics, no percentatges abstractes. Mostrar 'Analitzant funció withdraw(), pas 3 de 7' manté l'usuari a la pantalla durant el minut quatre. Una barra que passa de 41% a 43% no ho aconsegueix, i els percentatges honestos són impossibles quan no se sap quant durarà cada crida al model.
L'esdeveniment de troballa parcial és el que realment canvia la percepció del temps d'espera. En lloc d'esperar que acabi tota l'anàlisi, el backend envia cada troballa tan bon punt es valida. L'usuari comença a llegir el primer resultat mentre el model segueix treballant en la resta. El temps total no es redueix, però l'espera percebuda s'enfonsa. Si el teu treball llarg produeix resultats incrementals, transmetre'ls tan bon punt estan llests supera qualsevol barra de progrés. Però és crucial que aquestes troballes només s'enviïn després de passar una validació d'esquema al servidor; mai s'ha de transmetre escombraries al frontend. Validar abans d'emetre evita que errors del model arribin a la interfície.
La gestió d'errors també ha de ser explícita. Un error recuperable (per exemple, una fallada en una crida al model que es reintenta) ha de notificar-se a l'usuari sense aturar el treball. Un error fatal (pressupost exhaurit, entrada malformada) ha d'aturar el procés. L'esdeveniment d'error ha d'indicar clarament si és recuperable o no, perquè el frontend actuï en conseqüència: mostrar un missatge d'avís o redirigir a una pantalla d'error.
El major desafiament tècnic són les reconnexions. Els portàtils es tanquen, les xarxes canvien, els proxies tallen connexions inactives. En treballs de diversos minuts, la desconnexió és gairebé segura. EventSource es reconnecta automàticament enviant la capçalera Last-Event-ID amb l'últim esdeveniment rebut. Però aquesta capçalera només és útil si el servidor està preparat. Per això, cada esdeveniment ha de tenir un ID monòton creixent, i el servidor ha de mantenir un log reproducible d'esdeveniments per treball, independent de qualsevol connexió. Això obliga a una arquitectura on el treball no visqui dins de la petició HTTP. L'anàlisi s'executa en un procés durador (un worker, un consumidor de cua, un contenidor) que escriu esdeveniments en un emmagatzematge compartit. L'endpoint SSE és només un cursor sobre aquest log: reprodueix els esdeveniments que el client va perdre i després segueix en viu. Si el client es desconnecta a l'esdeveniment 12 i es reconnecta, rep des del 13 fins a l'estat actual, sense perdre res.
Un batec (heartbeat) en forma de comentari SSE (línies que comencen amb dos punts) manté la connexió viva durant llargs silencis del model, i la capçalera Cache-Control: no-transform impedeix que proxies benintencionats emmagatzemin en memòria intermèdia el flux.
Els entorns serverless presenten una dificultat addicional. Una funció Lambda o similar que mor en arribar al seu límit de temps no pot allotjar un treball de quatre minuts. Mantenir la funció viva mitjançant streaming només allarga el sostre, no l'elimina, i a més una desconnexió del client podria matar el treball per a tots els altres usuaris. La solució és separar el worker del stream: el treball s'executa en un entorn amb vida llarga (un worker process, un contenidor, un servei de cues), escriu esdeveniments en un emmagatzematge compartit, i l'endpoint SSE és una funció serverless barata i sense estat que només llegeix i reenvia. Així, el log és la font de veritat i la reconnexió funciona de manera natural.
Un altre aspecte crític és la contrapressió (backpressure). Quan un model local en una GPU ràpida emet esdeveniments més ràpid del que el navegador pot renderitzar, s'acumulen en un buffer. Per evitar-ho, es poden coalesir esdeveniments xerraires del costat del servidor: per exemple, agrupar actualitzacions de progrés en intervals curts i enviar només l'últim estat. Les troballes mai es coalesixen, cadascuna és important. A més, s'han de respectar els senyals del propi flux comprovant controller.desiredSize abans d'encuar esdeveniments de baixa prioritat, descartant ticks de progrés obsolets si el buffer s'omple.
A Q2BSTUDIO, apliquem aquests patrons en el desenvolupament d'aplicacions a mida que integren intel·ligència artificial, ciberseguretat i anàlisi de dades. Per exemple, una plataforma d'auditoria de contractes intel·ligents pot beneficiar-se d'aquest enfocament per oferir resultats parcials en temps real, millorant l'experiència de l'usuari sense augmentar la càrrega del servidor. També utilitzem serveis cloud a AWS i Azure per allotjar workers duradors que gestionen aquests treballs llargs, assegurant escalabilitat i fiabilitat. Els nostres agents d'IA es combinen amb dashboards de Power BI per visualitzar el progrés i les troballes de forma dinàmica.
El patró que ho uneix tot és tractar el log d'esdeveniments com el producte i la connexió SSE com una vista descartable del mateix. Cada problema difícil (reconnexió, límits serverless, contrapressió, múltiples pestanyes veient el mateix treball) es torna senzill una vegada que la connexió deixa de ser el lloc on resideix l'estat. Quin ha estat el treball més llarg que has hagut de mantenir al navegador, i què es va trencar primer? A la nostra experiència, el primer error sol ser la manca de retroalimentació primerenca, que porta l'usuari a interrompre el procés. Amb SSE i una arquitectura basada en logs, aquest problema desapareix.





