¿Qué es Symfony Messenger?

Messenger Symfony

Introducción a Symfony Messenger

Symfony Messenger es un componente diseñado para gestionar mensajes (comandos, eventos, tareas) de forma sincrónica o asíncrona mediante buses de mensajes. Su flexibilidad permite integrar transportes como AMQP (RabbitMQ), Doctrine (base de datos) o Redis, lo que lo convierte en una herramienta clave para aplicaciones escalables.

Algunos conceptos claves que hay que saber en el flujo de trabajo de Symfony Messenger.

Conceptos clave:

Concepto¿Qué es?
MessageUn objeto que representa una tarea a ejecutar.
HandlerClase que contiene el código para procesar ese mensaje.
BusCanal que enruta mensajes hacia sus handlers (command bus, etc.).
TransportMedio por el que se entregan los mensajes. Puede ser inmediato (sync) o encolado (async).
WorkerProceso que lee mensajes de una cola y los ejecuta.
retry_strategyConfigura cómo se reintentan mensajes en caso de fallo.

La Tabla messenger_messages

Cuando se usa Doctrine Transport, esta tabla almacena mensajes pendientes o fallidos. Campos relevantes:

CampoDescripción
idIdentificador único del mensaje.
bodyContenido del mensaje serializado (generalmente en JSON).
headersMetadatos (clase del mensaje, intentos, etc.).
queue_nameNombre del transporte/cola asociada (ej: asyncfailed).
delivered_atFecha en que un worker tomó el mensaje (si no es NULL, ya fue procesado).
available_atCuándo estará disponible para ser procesado (útil para mensajes retrasados).
created_atFecha de creación del mensaje.

Procesamiento Asíncrono: Flujo Paso a Paso

  1. Envío del Mensaje: $messageBus->dispatch(new UpdateExternalServiceCommand($data));
  2. Serialización y Almacenamiento
    Symfony serializa el mensaje y lo guarda en messenger_messages (si el transporte es Doctrine).
  3. Ejecución por el Worker bin/console messenger:consume async
  4. Manejo de Errores
    • Si el handler lanza una excepción, se aplica la retry_strategy.
    • Tras agotar los reintentos, el mensaje se mueve al Failure Transport (si está configurado).

Configuración de Reintentos Robustos

Ejemplo con retry exponencial y rate limiting:

# config/packages/messenger.yaml
framework:
  messenger:
    transports:
      async:
        dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
        retry_strategy:
          max_retries: 3
          delay: 2000    # 2 segundos iniciales
          multiplier: 2  # Delay exponencial: 2s → 4s → 8s
    failure_transport: failed
    
# config/packages/rate_limiter.yaml
    rate_limiter:
      api_limiter:
        policy: 'fixed_window'
        limit: 5
        interval: 1      # 5 llamadas por segundo

En el handler:

use Symfony\Component\Messenger\Attribute\AsMessageHandler;

#[AsMessageHandler]
class UpdateExternalServiceHandler
{
    public function __invoke(UpdateExternalServiceCommand $command)
    {
        $limiter = $this->rateLimiterFactory->create('api_limiter');
        if (!$limiter->consume()->isAccepted()) {
            throw new \RuntimeException('Límite de tasa excedido');
        }
        // Lógica para llamar al servicio externo
    }
}

Manejo de Mensajes Fallidos: Failure Transport

Configuración recomendada para entornos productivos:

  1. Definir el transporte de fallos framework: messenger: failure_transport: failed transports: failed: dsn: ‘doctrine://default?queue_name=failed’
  2. Crear tablas necesarias bin/console doctrine:migrations:migrate php bin/console messenger:setup-transports

Comandos Útiles

  • Listar mensajes fallidos: bin/console messenger:failed:show
  • Reintentar mensajes: bin/console messenger:failed:retry
  • Eliminar mensajes fallidos: bin/console messenger:failed:remove

¿Por Qué Usar el Failure Transport?

  • Auditoría: Conserva un registro de errores para análisis.
  • Recuperación: Permite reintentos manuales sin manipular la base de datos.
  • Seguridad: Evita pérdida de mensajes críticos.

Fuentes y Documentación Oficial

  1. Symfony Messenger: Procesamiento Asíncrono
  2. Configuración de Reintentos
  3. Manejo de Mensajes Fallidos
  4. Rate Limiter en Symfony


Symfony Messenger simplifica el manejo de tareas asíncronas y errores, pero requiere una configuración cuidadosa para garantizar robustez. Usando estrategias de reintento, rate limiting y el failure transport, puedes construir sistemas resilientes que se adapten a restricciones externas como límites de API.