Guía 22

Bases de datos y estado en bots: estado de conversación, sesiones, opciones de almacenamiento y retención

Desde fuera los bots parecen sin estado, pero cada flujo de varios pasos, ajuste y recordatorio necesita un sitio que sobreviva a los reinicios.

Guía2 min de lecturaActualizado

Qué guardar

  • Identidades: IDs de usuario y chat de la plataforma (como cadenas; los IDs de Telegram pueden superar los enteros de 32 bits y los snowflakes de Discord superan el rango seguro de enteros de JavaScript).
  • Preferencias: idioma, zona horaria (como nombre IANA), ajustes de notificaciones.
  • Estado de conversación: el paso actual de un flujo y las respuestas recogidas.
  • Tareas: recordatorios programados, difusiones pendientes, reintentos.
  • Claves de idempotencia: IDs de update o de evento procesados, para no tratar dos veces un webhook reenviado.

Guarda lo mínimo posible. No guardar el contenido de los mensajes evita toda una clase de problemas de privacidad.

Elegir almacenamiento

Necesidad Buena opción
Prototipo, un solo proceso Mapa en memoria (se pierde al reiniciar) o SQLite
Bot pequeño o mediano en un servidor SQLite en modo WAL o PostgreSQL
Varias instancias, datos relacionales PostgreSQL o MySQL
Sesiones, límites de tasa, bloqueos, datos con TTL corto Redis o Valkey
Entornos edge o serverless El almacén clave-valor de la plataforma, un SQL serverless o coordinación al estilo Durable Objects

Elige la opción aburrida que sepas respaldar. La mayoría de bots nunca superan una sola instancia de PostgreSQL.

Claves de sesión

Decide a quién pertenece una "sesión":

  • Por usuario para ajustes personales.
  • Por chat para funciones de grupo.
  • Por usuario en chat para flujos de varios pasos en grupos, para que dos personas rellenando un formulario a la vez no se pisen.

Frameworks como grammY, python-telegram-bot y Telegraf incluyen middleware de sesiones con adaptadores de almacenamiento intercambiables.

Modelar flujos

Guarda el flujo como una pequeña máquina de estados: {flow: "signup", step: "email", data: {...}, expires_at}. Añade una caducidad para que los flujos abandonados no atrapen a nadie y ofrece siempre /cancel. Diseña flujos visualmente con el diseñador de flujos.

Concurrencia

Las plataformas pueden entregar varios updates de un usuario casi a la vez (dobles toques, reintentos). Protege las secuencias de leer-modificar-escribir:

  • Usa transacciones o actualizaciones condicionales (UPDATE ... WHERE version = ?).
  • Procesa en secuencia los updates del mismo chat (una cola o un bloqueo por chat).
  • Registra los IDs de evento procesados con una restricción única y omite los duplicados.

Caché

Cachea los datos de la plataforma que lees a menudo (títulos de chat, roles) con un TTL corto y refréscalos con los eventos relevantes. Nunca uses una caché como fuente de verdad para permisos en acciones sensibles.

Operación

  • Versiona los cambios de esquema con una herramienta de migraciones y ejecútalos en CI/CD (CI/CD para bots).
  • Haz copias de seguridad periódicas y prueba a restaurarlas.
  • Define la retención: borra el estado de conversación caducado y elimina los datos de una persona cuando lo pida o bloquee el bot si tu política lo indica. Consulta aspectos legales, términos y privacidad.
  • Cifra los campos sensibles y mantén las credenciales de la base de datos fuera del código.

Comprueba lo aprendido

1. ¿Cómo guardar los snowflakes de Discord en apps JavaScript?
2. ¿Qué evita que los formularios de dos miembros de un grupo choquen?