montfort.dev
← ensayos

·8 min de lectura·#earthquake-alert #push-infra #distributed-systems #build-in-public

Cómo la alerta sísmica de la Ciudad de México llegó a los teléfonos en 2012

Un sismo de 7.5, un hermano mirando el cielo con calma y una sola pregunta: ¿por qué esta alerta no puede llegar a un teléfono? Cómo terminé operando el envío de push para medio millón de personas, y lo que eso me enseñó.

Esta historia empieza al mediodía del 20 de marzo de 2012, cuando un sismo de magnitud 7.5 sacudió las costas de Oaxaca, en el sur de México. Para la Ciudad de México fue el temblor más fuerte que se sintió desde la terrible mañana del 19 de septiembre de 1985.

Para 2012 la ciudad ya estaba cubierta por el Sistema de Alerta Sísmica Mexicano (SASMEX): una red de sensores sísmicos que convierte la física en tiempo de aviso. La ruptura se detecta cerca de la costa y, como las ondas sísmicas tardan en recorrer los ~300 km hasta el valle, la alerta puede llegar hasta sesenta segundos antes que el movimiento. En la ciudad se transmitía por estaciones de radio que corrían una implementación parcial del protocolo NWR SAME —el mismo que usa Estados Unidos para la radio meteorológica, esa que anuncia tornados y emergencias civiles— en frecuencias cercanas a los 162 MHz. Esas señales eran monitoreadas por receptores instalados en escuelas, oficinas de gobierno y postes de la calle conectados a altavoces que hacen sonar la alarma para todos los que estén cerca.

Todos los que estén cerca. Ese día yo estaba en casa con mi familia, y el altavoz más cercano quedaba a varias cuadras. No escuchamos nada. Lo que nos sacó de la casa fue el propio movimiento: la mitad del agua de mi acuario de 120 litros terminó en el suelo, junto con casi todos nuestros libreros. Afuera, en el patio, todos estaban asustados, buscando de qué sostenerse mientras la tierra se movía; todos menos mi hermano Emiliano, que estaba parado tranquilo, mirando el cielo. Cuando la tierra se calmó, se volteó hacia mí, sereno, y dijo:

Deberíamos averiguar cómo se transmite realmente la alerta sísmica. Es peligroso que esas bocinas no se alcancen a oír. Podríamos mandar la alerta a los teléfonos.

Fue difícil, porque casi no había información pública sobre cómo funcionaba la alerta. La pieza que lo destrabó todo fue un PowerPoint, escrito por un empleado del SASMEX e indexado por accidente en un servidor universitario. A partir de ahí, dos compras que en ese momento fueron todo un esfuerzo para nosotros: un receptor de alerta sísmica SARMEX —el único proveedor autorizado para vender receptores con grado de cumplimiento para protección civil en México— por unos 300 dólares, un iPhone 4 por unos 600, y un Mac mini por cerca de 800. Y luego un largo camino de experimentación: desde decodificar un mensaje digital escondido dentro de una señal de audio de radio, hasta entregar notificaciones remotas a un iPhone.

Decodificar la señal

Hice varios experimentos para decodificar los mensajes NWR SAME, y todos fallaron de la misma manera. Logré un prototipo en C++ que cumplía el protocolo sobre el papel, pero nunca pude optimizarlo lo suficiente para que funcionara ni cerca de tiempo real, y para una alerta sísmica “casi en tiempo real” es lo único que cuenta.

Lo que me salvó fue un proveedor de CTI —integración de telefonía y cómputo— que vendía un control ActiveX sobre .NET Framework 4 que, entre otros protocolos, decodificaba NWR SAME. Lo compré y escribí un programa alrededor de él. Era eficiente, era confiable, y estaba listo. Pero decodificar la alerta nunca fue el verdadero reto. El reto era llevarla a los teléfonos.

Hablar con los teléfonos

Esto era prácticamente la prehistoria del cómputo móvil. iOS 5 corría en el iPhone 4; Android 4 apenas empezaba a ser un sistema operativo usable. Las notificaciones remotas eran nuevísimas, y eran primitivas.

El APNs de Apple no tenía broadcast: solo unicast. Si quería notificar a mil usuarios, escribía un loop y hacía mil solicitudes individuales. Android, por su parte, acababa de lanzar GCM (Google Cloud Messaging, el ancestro de Firebase Cloud Messaging), que reemplazó a C2DM y tenía una función que a APNs le faltaba: multicast limitado. Podía enviar una lista de hasta mil device IDs en una sola solicitud. 2012 fue también el año en que los usuarios migraron en masa de BlackBerry a iPhone y Android, así que no me preocupé por esa tercera plataforma.

Un lugar donde guardar los dispositivos

Así que podía enviar notificaciones: una por una a los iPhones, en lotes de mil a Android. Pero primero tenía que registrar cada device ID en algún lugar que pudiera consultar cuando llegara una alerta. Escribí un pequeño servidor en PHP que exponía dos endpoints: uno para recibir registros de dispositivos, otro para recibir alertas sísmicas del decodificador. Los datos vivían en MySQL.

Ese era todo el sistema: un decodificador y una antena en mi casa, y un servidor de base de datos corriendo en hosting compartido de una empresa alemana. Y todo funcionó bien, hasta que dejó de funcionar.

Y entonces llegaron los usuarios

El sistema estuvo bien para los primeros 100 usuarios. Con 1,000 se probó a sí mismo y aguantó. Con 50,000, las notificaciones empezaron a tardar hasta dos minutos en llegar, sobre todo a los iPhones. La primera salía casi al instante, pero salían una por una, y vaciar la lista completa tomaba dos minutos. Todo esto en las primeras tres semanas tras el lanzamiento.

Así que cambié el stack. Reemplacé PHP + MySQL por Python Tornado + MongoDB, porque necesitaba recuperar cada milisegundo que pudiera, y me mudé del hosting compartido alemán a un servidor dedicado en Estados Unidos para ahorrar ping. Eso me dio los siguientes 50,000 usuarios —a lo largo del segundo mes— hasta que volvió a colapsar. La lista de iPhones seguía tardando una eternidad en procesarse.

Esta vez medí antes de reescribir, y la medición cambió el enfoque: el servidor no estaba en su límite. El software simplemente no podía procesar una sola lista más rápido. Así que tomé prestado el propio modelo de Android —lotes de mil— y lo construí yo mismo para APNs. Escribí un dispatcher que corría varias instancias de Tornado, cada una con su propio ID que le indicaba qué lote le tocaba. Cada instancia jalaba su propia rebanada de mil usuarios desde MongoDB y la procesaba en paralelo con las demás.

# Cada instancia es dueña de una rebanada según su id; vacían MongoDB en paralelo.
# Una alerta sísmica que llega tarde no llega tarde: llega mal.
async def dispatch(instance_id, total_instances):
    cursor = devices.find({"shard": instance_id % total_instances})
    async for batch in chunks(cursor, 1000):
        await apns.send(batch, payload=ALERT)   # una instancia, una rebanada

Y todo funcionó bien, hasta que dejó de funcionar.

Aprender sistemas distribuidos a golpes

El crecimiento fue enorme. La app rebasó los 500,000 usuarios. Con el tiempo construí orquestadores para correr varios servidores dedicados, cada uno con múltiples instancias de notificación, y aprendí a configurar y operar sharding en MongoDB; todo dentro de los primeros ocho a doce meses del proyecto.

Fue el tramo de trabajo más intenso que había hecho en mi vida, bajo la amenaza permanente de sistemas corriendo hacia su techo operativo. Y había un peso más grande debajo del técnico: el público lo trataba como un servicio de emergencia, aunque siempre se ofreció como experimental, una forma de promover una cultura de protección civil. Nunca había trabajado a ese ritmo, y no volvería a hacerlo hasta que la IA se volvió genuinamente útil para trabajo serio, a finales de 2025.

Lo que las plataformas lanzaron después

Mi preocupación por mantener vivo un sistema distribuido terminó años después, y terminó porque las plataformas alcanzaron al proyecto. En 2016 Android obtuvo multicast de verdad: los usuarios podían suscribirse a canales de notificación, así que mi sistema enviaba una sola notificación a un canal y el nuevo Firebase Cloud Messaging hacía el resto. Apple mejoró APNs ese mismo año con una API HTTP/2 que aceptaba lotes de hasta 50,000 dispositivos, lo que me permitió colapsar todo de regreso a un solo servidor de notificaciones que guardaba listas en caché para envíos por lotes.

Quiero ser preciso sobre lo que esto significa, porque sería fácil exagerar. No fui el primero, y no estuve solo: ya había empresas cuyo negocio entero era el envío masivo de push como servicio, y pagar para salir del problema siempre fue una opción. Yo simplemente quería construir el mío. Y al construirlo, bajo fuego, con una antena en mi sala, terminé armando a mano exactamente las cosas que las plataformas harían nativas después: entrega por shard por instancia, envíos por lotes, canales de suscripción. Durante unos años corrí, por necesidad, la infraestructura que los gigantes terminarían lanzando como una casilla que se palomea.

Esa es la parte que me quedo. No los números de throughput —esos quedaron obsoletos en el momento en que Apple y Google decidieron que el problema valía la pena resolverlo ellos mismos—. Lo que se me quedó es la forma de pensar que el proyecto me obligó a adoptar: mide antes de reescribir; diseña el modo de falla antes que la función; respeta la distancia entre lo que prometes y cómo la gente realmente usa lo que construiste. Aprendí sistemas distribuidos a golpes —sharding, orquestación, back-pressure—, pero la lección más duradera fue que construir algo tú mismo, cuando podrías haberlo comprado, es como aprendes dónde están de verdad los bordes filosos. Es el mismo instinto que me puso donde estoy ahora, construyendo gobernanza para sistemas que, una vez más, la mayoría preferiría tratar como una caja negra.

El final

Mantuve el sistema funcionando hasta septiembre de 2025, cuando llegó Cell Broadcast para SASMEX —la alerta ahora llega directo a todos los teléfonos celulares, sin necesidad de app— y volvió obsoleta la notificación push de la noche a la mañana.

No me importó. El trabajo de un proyecto como este siempre fue volverse innecesario. A las plataformas les tomó cuatro años igualarlo y a las autoridades trece retirarlo, y en algún lugar de la Ciudad de México sigue habiendo un hermano que miró el cielo en lugar del suelo, y que hizo primero la pregunta correcta.

Gracias por leer. Publico cuando hay algo que valga tu tiempo —rss.xml es el contrato. ConstruyoStrayMark en público; el próximo ensayo probablemente sea sobre eso.