0Pricing
PHP Academy · Aula

Por que usar mensageria assíncrona

Veja como as filas desacoplam produtores e consumidores.

Por que usar mensageria assíncrona é uma aula grátis de PHP Academy no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de PHP Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de PHP Academy inclui 4 aulas no total.

Por que usar mensagens assíncronas

Em uma solicitação síncrona, seu processo PHP fica bloqueado enquanto se comunica com gateways de e-mail, processadores de pagamentos ou serviços dependentes. Sob carga, isso vincula sua latência e disponibilidade a cada dependência chamada. As mensagens assíncronas rompem essa cadeia: o produtor coloca uma mensagem em uma fila e retorna imediatamente; os consumidores a processam mais tarde, no próprio ritmo.

Esta lição aborda o motivo — desacoplamento, armazenamento temporário e as concessões das garantias de entrega que você precisa avaliar antes de usar RabbitMQ ou Kafka.

Desacoplamento temporal e espacial

Uma fila desacopla produtores e consumidores em dois eixos:

  • Espacial — nenhum dos lados precisa do endereço do outro; ambos conhecem apenas o intermediário.
  • Temporal — o consumidor pode estar indisponível quando o produtor publica; a mensagem aguarda.

A versão síncrona abaixo vincula a solicitação web à disponibilidade e à velocidade do servidor de e-mail.

<?php
// Synchronous: the HTTP request blocks on SMTP
function registerUser(string $email): void {
    saveUser($email);
    // If SMTP is slow or down, the user waits or the request fails
    sendWelcomeEmail($email); // 800ms blocking call
    echo "Registered\n";
}

function saveUser(string $e): void { /* ... */ }
function sendWelcomeEmail(string $e): void { usleep(1); }

registerUser('dev@example.com');

Publique e prossiga

A versão assíncrona persiste o usuário, publica uma mensagem UserRegistered e retorna. Um trabalhador separado envia o e-mail. Agora, a latência HTTP depende apenas de uma publicação rápida no intermediário local, não da ida e volta pelo SMTP.

<?php
function registerUser(string $email): void {
    saveUser($email);
    // Publish a lightweight event; worker handles email later
    publish('user.registered', json_encode(['email' => $email]));
    echo "Registered (email queued)\n";
}

function saveUser(string $e): void { /* ... */ }
function publish(string $routingKey, string $payload): void {
    echo "-> queued $routingKey: $payload\n";
}

registerUser('dev@example.com');

Nivelamento de carga (armazenamento temporário)

Os picos de tráfego são irregulares; a capacidade de processamento é fixa. Uma fila atua como um amortecedor: absorve um pico de 10.000 mensagens e permite que um conjunto de trabalhadores as processe a uma taxa sustentável. Sem uma fila, o pico sobrecarregaria diretamente o banco de dados ou a API dependente.

Isso é nivelamento de carga — você troca latência (as mensagens podem aguardar brevemente) por estabilidade (nada falha).

Garantias de entrega

Todo sistema de mensagens faz uma promessa de entrega. Saiba qual é a sua:

  • No máximo uma vez — envie e esqueça; as mensagens podem ser perdidas, mas nunca são duplicadas.
  • Pelo menos uma vez — são reenviadas até serem confirmadas; duplicatas são possíveis. Essa é a configuração padrão mais comum.
  • Exatamente uma vez — sem perdas nem duplicatas; é caro e frequentemente uma ilusão parcial na camada da aplicação.

Como a maioria dos sistemas reais oferece pelo menos uma vez, seus consumidores precisam tolerar receber a mesma mensagem duas vezes.

Consumidores idempotentes

A solução para as duplicatas da entrega pelo menos uma vez é a idempotência: processar uma mensagem duas vezes produz o mesmo resultado que processá-la uma vez. A técnica usual é armazenar uma chave de deduplicação (o ID da mensagem) em um índice exclusivo.

<?php
function handle(array $msg, PDO $pdo): void {
    $pdo->beginTransaction();
    try {
        // Unique constraint on message_id makes the insert the dedup gate
        $stmt = $pdo->prepare(
            'INSERT INTO processed_messages (id) VALUES (?)'
        );
        $stmt->execute([$msg['id']]);
    } catch (PDOException $e) {
        $pdo->rollBack();
        echo "Duplicate {$msg['id']} skipped\n";
        return; // already handled
    }
    chargeCustomer($msg['amount']);
    $pdo->commit();
}
function chargeCustomer(int $a): void {}

Confirmações e reentrega

Um consumidor sinaliza sucesso com uma confirmação. Se ele falhar antes de confirmar, o intermediário reentrega a mensagem a outro consumidor. É isso que faz a entrega pelo menos uma vez funcionar — mas significa que um ack deve ocorrer depois que o efeito colateral for confirmado, nunca antes.

Envie a confirmação cedo demais e uma falha perderá a mensagem. Envie-a tarde demais (e ocorra uma falha) e você terá uma duplicata — que sua camada de idempotência absorverá.

<?php
// Pseudocode of the consumer contract
function consumeLoop($channel): void {
    while ($msg = $channel->get()) {
        try {
            processSideEffect($msg);   // commit DB write first
            $channel->ack($msg);       // only then ack
        } catch (\Throwable $e) {
            $channel->nack($msg, requeue: true); // let it redeliver
        }
    }
}
function processSideEffect($m): void {}

A ordenação não é gratuita

As filas não garantem ordenação global quando você escala horizontalmente os consumidores. Dois trabalhadores que retiram mensagens da mesma fila as processam em concorrência, portanto a mensagem B pode terminar antes da mensagem A.

Se a ordem for importante (por exemplo, alterações no saldo de uma conta), você precisará particionar por chave para que todas as mensagens relacionadas sejam encaminhadas em sequência a um único consumidor. O Kafka faz isso nativamente com partições; com o RabbitMQ, encaminhe usando uma função hash consistente para filas por chave.

Filas de mensagens mortas

Algumas mensagens nunca poderão ser processadas com sucesso — cargas inválidas ou referências a registros excluídos, por exemplo. Tentar processá-las indefinidamente trava a fila (uma mensagem venenosa). O padrão é uma fila de mensagens mortas (DLQ): após N tentativas malsucedidas, encaminhe a mensagem para outro local para inspeção, em vez de reenviá-la.

<?php
function consume(array $msg, $channel): void {
    $attempts = ($msg['headers']['x-attempt'] ?? 0) + 1;
    try {
        process($msg);
        $channel->ack($msg);
    } catch (\Throwable $e) {
        if ($attempts >= 5) {
            $channel->deadLetter($msg); // park in DLQ
        } else {
            $channel->republish($msg, ['x-attempt' => $attempts]);
        }
    }
}
function process(array $m): void {}

Quando NOT usar uma fila

As mensagens assíncronas acrescentam um custo operacional real: um intermediário para operar, consistência eventual para explicar à equipe de produto e depuração mais difícil entre limites de processos.

Escolha uma fila quando o trabalho for lento, sujeito a picos, passível de nova tentativa ou de envio e esquecimento. Mantenha-o síncrono quando o chamador realmente precisar do resultado agora (por exemplo, um preço oficial que o usuário precisa ver) — colocar em uma fila uma chamada que precisa de resposta apenas acrescenta latência e complexidade.

Fila versus registro

Dois formatos amplos de intermediário dão suporte a esses padrões, e o restante deste curso usa ambos:

  • Uma fila de tarefas (RabbitMQ) exclui uma mensagem assim que ela é confirmada. Ela é excelente para distribuir trabalho a um conjunto de consumidores concorrentes, com roteamento por mensagem e tempos de expiração.
  • Um registro de transações (Kafka) mantém as mensagens durante o período de retenção; cada consumidor acompanha seu próprio deslocamento e pode reproduzir o histórico, enquanto muitos grupos independentes de consumidores leem o mesmo fluxo.

Escolha a fila para distribuir trabalho e o registro para fluxos de eventos de alta vazão e reprodução.

<?php
$useCase = 'replay events for a new analytics service';
$broker = str_contains($useCase, 'replay') || str_contains($useCase, 'stream')
    ? 'Kafka (commit log)'
    : 'RabbitMQ (task queue)';
echo $broker . "\n";

Verificação rápida

Raciocinando sobre garantias de entrega.

Recapitulação

Agora você tem o modelo mental por trás das mensagens assíncronas:

  • As filas fornecem desacoplamento espacial e temporal e atuam como um amortecedor para o nivelamento de carga.
  • A maioria dos sistemas oferece pelo menos uma vez, portanto os consumidores precisam ser idempotentes.
  • Envie a confirmação depois que o efeito colateral for confirmado; permita que as falhas provoquem uma reentrega.
  • A ordenação exige particionamento por chave; mensagens venenosas exigem uma DLQ.
  • Não coloque em uma fila o trabalho cuja resposta o chamador precisa receber de forma síncrona.

Em seguida, você colocará isso em prática com RabbitMQ no PHP.

Perguntas Frequentes

A aula “Por que usar mensageria assíncrona” é grátis?

Sim — o texto completo de “Por que usar mensageria assíncrona” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de PHP Academy, atualize para CoddyKit PRO. O curso de PHP Academy inclui 4 aulas no total.

O que vou aprender em “Por que usar mensageria assíncrona”?

Veja como as filas desacoplam produtores e consumidores. Você pratica PHP Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar PHP Academy?

Nenhuma experiência prévia é necessária. PHP Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.

Quanto tempo leva a aula “Por que usar mensageria assíncrona”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de PHP Academy?

Sim. Cada aula de PHP Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Por que usar mensageria assíncrona
  2. Trabalhando com RabbitMQ em PHP
  3. Apache Kafka com PHP
  4. Construindo fluxos de trabalho orientados a eventos
← Voltar para PHP Academy