Usando RabbitMQ com MonsterMQ Parte 3

Em nosso artigo anterior, criamos uma fila de tarefas. Ele pressupõe que uma tarefa na forma de uma mensagem seja entregue a um destinatário. Neste artigo, faremos outra coisa; enviaremos uma mensagem para vários destinatários ao mesmo tempo. Criaremos um sistema de registro que consistirá em dois programas: o primeiro enviará mensagens e o segundo as receberá e exibirá. Em nosso sistema, todos os destinatários em execução receberão uma mensagem enviada pelo remetente.

Trocas (trocadores)


Nos artigos anteriores, enviamos e recebemos mensagens de filas, agora é hora de introduzir um modelo completo de encaminhamento de mensagens no RabbitMQ.

Vamos analisar rapidamente o que abordamos nos artigos anteriores:

  • Producer - um aplicativo que envia mensagens
  • Fila - um buffer que armazena mensagens
  • Consumidor - um aplicativo que recebe e processa mensagens

A idéia principal do RabbitMQ (ou melhor, do AMQP) é que o remetente (produtor) nunca envie uma mensagem diretamente para a fila. Além disso, ele nem sabe se está na fila. Em vez disso, o remetente envia mensagens para os trocadores (Exchange). O trocador é uma coisa muito simples, ele faz duas coisas: recebe uma mensagem dos remetentes e os redireciona para a fila. Os trocadores são de tipos diferentes: alguns enviam mensagens para uma fila específica (tipo direto), outros enviam a mesma mensagem para várias filas ao mesmo tempo (tipo de fanout), outros redirecionam mensagens para uma fila com base em regras de redirecionamento específicas e especificadas (tipo de tópico).

imagem
(imagem retirada do site oficial do RabbitMQ )

Vejamos um trocador do tipo fanout. Para criá-lo, escreva o seguinte código:

$producer->newFanoutExchange('logs');

O trocador Fanout funciona de acordo com um esquema muito simples, simplesmente envia a mensagem recebida a todas as filas anexadas a ele.

Para listar todos os trocadores existentes no servidor, chame rabbitmqctl

sudo rabbitmqctl list_exchanges

Esta lista conterá amq. * Trocadores e um trocador sem nome (linha vazia) padrão. Não preste atenção neles, ainda não precisamos deles.

No último artigo, não sabíamos nada sobre trocadores, mas mesmo assim conseguimos enviar mensagens. Isso aconteceu porque se no MonsterMQ você não especificar explicitamente o trocador como o terceiro argumento para o método Producer :: publish () , a biblioteca usará o trocador sem nome padrão RabbitMQ, que envia mensagens em filas cujos nomes são passados ​​como segundo argumento para o método Producer :: publish () .

Agora podemos enviar mensagens para o nosso novo trocador, especificando seu nome como o terceiro argumento para o método Producer :: publish () :

$producer->publish($message, '', 'logs');

Agora, vamos criar dois trabalhadores com duas filas que existirão enquanto os trabalhadores que os anunciaram estiverem ativos. Você pode fazer isso da seguinte maneira:

//Worker 1
$producer->queue('queue-1')->setExclusive()->declare();

//Worker 2
$producer->queue('queue-2')->setExclusive()->declare();

Agora, quando o trabalhador que anunciou a fila terminar a sessão e desconectar, ela será excluída automaticamente. Se os dois trabalhadores concluírem o trabalho, as duas filas serão excluídas.

Conectamos a fila ao trocador


Já criamos uma troca e uma fila. Agora só precisamos dizer ao trocador para enviar as mensagens recebidas para nossas filas. Precisamos ligar o trocador e as filas. Para fazer isso, escreva o seguinte código:

//Worker 1
$producer->queue('queue-1')->bind('logs');

//Worker 2
$producer->queue('queue-2')->bind('logs');

A partir de agora, nosso trocador de logs estará conectado às nossas filas e encaminhará as mensagens recebidas para eles.

Você pode listar todos os links existentes com o seguinte comando no linux

rabbitmqctl list_bindings

Juntando o código


Nosso script de remetente não mudou muito em comparação com a lição anterior. A principal diferença é que agora ele envia mensagens para o trocador anunciado anteriormente, e não para o padrão (acessível a partir da caixa). Aqui está o código send.php

try {
   $producer = \MonsterMQ\Client\Producer();

   $producer->connect('127.0.0.1', 5672);
   $producer->logIn('guest', 'guest');

   $producer->newFanoutExchange('logs');

   $message = implode(' ', array_slice($argv, 1));
   $message = empty($message) ? 'Hello world!' : $message;

   $producer->publish($message, '', 'logs');

   echo "\n Sent {$message} \n";
} catch(\Exception $e) {
   var_dump($e);
}

Vale ressaltar que, ao enviar uma mensagem para um trocador que não está associado a nenhuma fila, a mensagem será perdida. Mas agora isso nos convém, pois ainda não lançamos nossos destinatários.

Aqui está o código para o nosso primeiro worker-1.php worker

try {
   $consumer = \MonsterMQ\Client\Consumer();

   $consumer->connect('127.0.0.1', 5672);
   $consumer->logIn('guest', 'guest');

   $producer->queue('queue-1')->setExclusive()->declare();
   $producer->queue('queue-1')->bind('logs');

   $consumer->consume('queue-1');

   $consumer->wait(function ($message, $channelNumber) use ($consumer){
      echo "\n $message \n";
   });
} catch(\Exception $e) {
   var_dump($e);
}

Aqui está o código para o segundo trabalhador-2.php

try {
   $consumer = \MonsterMQ\Client\Consumer();

   $consumer->connect('127.0.0.1', 5672);
   $consumer->logIn('guest', 'guest');

   $producer->queue('queue-2')->setExclusive()->declare();
   $producer->queue('queue-2')->bind('logs');

   $consumer->consume('queue-2');

   $consumer->wait(function ($message, $channelNumber) use ($consumer){
      echo "\n $message \n";
   });
} catch(\Exception $e) {
   var_dump($e);
}

Se você deseja salvar as mensagens enviadas para o primeiro trabalhador em um arquivo de log, basta chamar o seguinte comando no console:

php worker-1.php > logs_from_rabbit.log

Para iniciar os trabalhadores e exibir mensagens nas janelas do terminal, chame os seguintes comandos, cada um em sua própria janela:

php worker-1.php

php worker-2.php

E para enviar mensagens, chame o seguinte comando:

php send.php

Na próxima lição, veremos como obter apenas um determinado subconjunto de mensagens de todas as enviadas.

All Articles