Etiqueta: event-driven

  • Notificaciones PHP en tiempo real con Redis y WebSockets

    Notificaciones PHP en tiempo real con Redis y WebSockets

    Resumen: guía práctica para enviar notificaciones en tiempo real desde PHP usando Redis como bus de mensajes y WebSockets para entrega instantánea. Incluye ejemplo mínimo, buenas prácticas y checklist de despliegue.

    Introducción

    Las notificaciones en tiempo real son fundamentales para la experiencia de usuario moderna. En vez de pollings periódicos, una combinación de Redis (Pub/Sub o Streams) y un servidor WebSocket permite entregar mensajes al instante desde PHP.

    Prerrequisitos

    • PHP con soporte para ejecución de procesos permanentes (p. ej. Workerman, Swoole o Ratchet)
    • Redis (instancia accesible desde el servidor WebSocket)
    • Cliente Redis para PHP (Predis o phpredis) y composer
    • Clientes Web que soporten WebSockets y lógica de reconexión

    Desarrollo

    La arquitectura básica separa responsabilidades: la aplicación PHP publicará eventos en Redis; un proceso WebSocket suscrito a Redis retransmitirá esos mensajes a los clientes conectados.

    Procedimiento

    Pasos esenciales:

    1. Publicar un evento en Redis desde la app PHP cuando ocurre la acción (por ejemplo, comentario nuevo).
    2. El proceso WebSocket está suscrito al canal Redis y recibe el evento.
    3. El proceso WebSocket envía el payload a los clientes conectados (filtrando por usuario o canal si aplica).
    4. El cliente maneja el mensaje (mostrar notificación, solicitar detalles, marcar como leído, etc.).

    Ejemplo mínimo de servidor WebSocket en PHP usando Workerman y Predis (suscripción a Redis y broadcast a conexiones activas).

    <?php
    use Workerman\Worker;
    use Predis\Client as RedisClient;
    
    require 'vendor/autoload.php';
    
    $ws = new Worker("websocket://0.0.0.0:8080");
    $ws->count = 1;
    
    $redis = new RedisClient();
    
    $ws->onWorkerStart = function() use ($ws, $redis) {
        $pubsub = $redis->pubSubLoop();
        $pubsub->subscribe('notifications');
        foreach ($pubsub as $message) {
            if ($message->kind === 'message') {
                foreach ($ws->connections as $connection) {
                    $connection->send($message->payload);
                }
            }
        }
    };
    
    Worker::runAll();
    Lenguaje del código: PHP (php)

    Este proceso mantiene una conexión permanente a Redis y distribuye cada mensaje recibido a todas las conexiones WebSocket. En producción conviene no enviar todo el payload a todos los clientes: filtrar por canal/usuario.

    Ejemplo de publicación de un evento desde la aplicación PHP usando Predis.

    <?php
    use Predis\Client as RedisClient;
    
    $redis = new RedisClient();
    
    $event = json_encode([
        'type' => 'comment_created',
        'user_id' => 42,
        'data' => ['id' => 123, 'excerpt' => 'Nuevo comentario']
    ]);
    
    $redis->publish('notifications', $event);
    Lenguaje del código: PHP (php)

    En el ejemplo anterior publicamos en un canal genérico ‘notifications’. Para evitar sobre-broadcasting, use canales por usuario o por topic (p. ej. notifications:user:42).

    Ejemplos

    Cliente JavaScript: conexión WebSocket básica con reconexión y manejo de mensajes ligeros (solo resumen; adapte según su app).

    function createSocket(url) {
      let ws;
      let retry = 1000;
    
      function connect() {
        ws = new WebSocket(url);
    
        ws.onopen = () => {
          retry = 1000; // reset backoff
          console.log('WS connected');
        };
    
        ws.onmessage = (ev) => {
          const msg = JSON.parse(ev.data);
          // manejar evento: mostrar notificación o solicitar detalles
          console.log('evento', msg);
        };
    
        ws.onclose = () => {
          console.log('WS closed, reconnecting in', retry);
          setTimeout(connect, retry);
          retry = Math.min(30000, retry * 2);
        };
    
        ws.onerror = (err) => {
          console.error('WS error', err);
          ws.close();
        };
      }
    
      connect();
      return () => ws && ws.close();
    }
    
    // uso
    const stop = createSocket('wss://example.com:8080');
    Lenguaje del código: JavaScript (javascript)

    Consejo: mantenga los payloads ligeros. Enviar solo el ID del evento o un resumen reduce latencia y consumo de ancho de banda.

    Redis + WebSockets transforman un backend PHP tradicional en un canal de notificaciones cercano a tiempo real, sin necesidad de reescrituras completas.

    Checklist

    1. Usar canales por usuario o topic para evitar sobre-broadcast.
    2. Autenticar y autorizar suscripciones (gateway o tokens JWT).
    3. Implementar reconexión y reintentos en cliente.
    4. Considerar Redis Streams si necesita persistencia y replay de mensajes.
    5. Monitoreo del proceso WebSocket y alertas para reinicio automático.
    6. Limitar tamaño del payload y evitar enviar datos sensibles por el socket.

    Conclusión

    Combinar Redis y WebSockets permite a aplicaciones PHP ofrecer notificaciones instantáneas sin depender de polling. El patrón reduce latencia y escala bien si se aplica filtrado por canales, autenticación y manejo de fallos.

    Empiece con un prototipo mínimo (un proceso WebSocket suscrito a Redis) y evolucione a Streams, balanceo y autenticación según las necesidades de producción.