Mantener vivo el chat cuando el móvil se duerme
El agente de Mythex puede trabajar minutos seguidos en una petición, y es probable que estés siguiéndolo desde el móvil, que se bloquea, cambia de app y cambia de red mientras trabaja. Dos fallos estropeaban eso. En uno, el chat trataba cada señal de «la página vuelve a estar visible» como prueba de que su conexión se había caído, y entraba en bucle hasta quedarse en «Conectando…». En el otro, un móvil que se durmió durante la primera respuesta de un chat nuevo volvía a mostrar solo los primeros trozos, hasta que se refrescaba la página a mano. Ambos están arreglados.
Cómo sigue el chat un turno en marcha
Mientras el agente trabaja, el chat mantiene abierto un stream desde nuestros servidores: cada paso —un pensamiento, una llamada a herramienta, un fragmento de la respuesta— llega como un evento. Si el stream se corta, el chat se reconecta y el servidor reproduce los eventos recientes desde un búfer que guarda los últimos 120 segundos. Cuando el turno termina, el chat además pide al servidor el historial guardado y concilia lo que había mostrado con lo que se almacenó. Ese último paso atrapa lo que el stream se perdió.
Para distinguir una conexión viva de una muerta mientras no pasa nada, el servidor envía un pequeño «ping» cada 15 segundos.
Fallo 1: despertar mataba un stream sano
Los navegadores avisan a una página cuando vuelve a ser visible: tras cambiar de pestaña, tras desbloquear la pantalla. Lo usábamos como señal para comprobar la conexión y, en la práctica, para abortar el stream y reconectar, suponiendo que se había caído mientras la página estaba oculta.
En los móviles y en los navegadores embebidos, estos eventos se disparan mucho más a menudo de lo que se caen los streams: en cada cambio de pestaña, en cada desbloqueo, y en algunos navegadores embebidos cada par de segundos más o menos. Cada uno abortaba un stream perfectamente sano. El chat se reconectaba, reproducía, volvía a ser abortado y terminaba quedándose en «Conectando…». Después decía que el turno había terminado mientras el agente seguía trabajando.
La solución: juzgar el stream por si está hablando
Ahora el chat registra cuándo el stream de cada proyecto recibió por última vez cualquier cosa, tanto eventos como los pings de 15 segundos. Una señal de «visible otra vez» solo aborta un stream que lleva 25 segundos en silencio: más que el intervalo de ping más un salto lento de red, así que un stream vivo nunca cumple la condición. Las pruebas comprueban que un ping cuenta como señal de vida, y que un stream que acaba de hacer ping no se trata como muerto.
La regla que sacamos de ello: la visibilidad de una página dice algo de la página, no de la conexión de red. Pregúntale a la conexión.
Fallo 2: media respuesta después de despertar el móvil
Este pudimos reproducirlo siempre en el simulador de iOS:
- Empieza un chat nuevo y envía una petición que tarde un poco.
- Deja que el móvil se duerma durante la construcción.
- Vuelve cuando el turno ya ha terminado y el búfer de reproducción de dos minutos ha caducado.
El chat mostraba los primeros bloques de la respuesta, marcados como terminados, y se quedaba así hasta refrescar la página.
Por qué
Un chat nuevo no tiene hilo —su conversación guardada— hasta que el primer mensaje lo crea. Eso ocurre dentro de la función de envío, después de que el envío ya hubiera capturado el paso de conciliación, que seguía creyendo que no había hilo. Así que al final del primer turno de un chat nuevo, la conciliación veía que no había hilo y volvía en silencio sin pedir nada.
Normalmente nadie lo notaba, porque el stream había entregado el turno completo de todos modos. Pero un móvil que se durmió durante el turno y volvió después de que el búfer de reproducción de 120 segundos hubiera caducado no podía recuperar los eventos que faltaban desde el stream, y la conciliación que debía cubrir el hueco nunca se había ejecutado.
La solución
- El envío le dice a la conciliación a qué hilo pertenece el turno, así que el primer turno de un chat nuevo se concilia como cualquier otro. Si para cuando llega la respuesta has abierto otro chat, el resultado se descarta en lugar de mostrarse en el sitio equivocado.
- Una conciliación fallida se reintenta. Un móvil que despierta con una conexión mala puede encontrar que el turno ya terminó y luego fallar al obtenerlo. Eso ahora se recuerda, y el chat vuelve a intentarlo cuando se muestra la pestaña de nuevo o cuando vuelve la red.
- «Trabajó durante» es honesto. Cada respuesta muestra cuánto tiempo trabajó el agente. Si pestaña nunca vio el mensaje de fin de turno del servidor, antes se rellenaba con su propio reloj, que contaba desde Enviar hasta que el móvil despertó —incluido el tiempo fuera—. Ese dato ahora se marca como estimación, y se sustituye por la duración guardada en cuanto llega el historial.
Lo que aprendimos
- Prueba en el dispositivo que la gente usa, de la forma en que lo usa. Ambos fallos vivían en el hueco entre «un stream que funciona» y «un móvil en el bolsillo».
- Un respaldo que nunca se ejecuta no es un respaldo. La conciliación existía precisamente para atrapar este caso, y lo saltaba en silencio.
- Reintenta también la recuperación. El momento en que despierta un móvil es a menudo cuando su conexión está peor.
- No muestres una suposición como un hecho. Una duración tomada del reloj equivocado es peor que no mostrar nada; márcala como estimación o reemplázala.
Lo mismo de este trabajo también ordenó algunas cosas que verás mientras un turno se ejecuta: los pasos de shell se etiquetan por el comando que hace el trabajo en lugar de cd, las capturas de pantalla en el chat conservan la esquina superior izquierda de la página y encajan en la columna, y un proyecto nuevo recoge su nombre generado sin refrescar la página.
Si estás creando tu propia app para móviles, nuestras guías sobre cómo construir una app web adaptada al móvil y apps nativas frente a apps web progresivas cubren lo básico. Más sobre el propio chat está en la documentación del chat.