PHP Academy · Lezione

Utilizzare RabbitMQ in PHP

Pubblicate e consumate messaggi con RabbitMQ.

Lezione 2 di 413 passaggi

Utilizzare RabbitMQ in PHP è una lezione PHP Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento PHP Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso PHP Academy include 4 lezioni in totale.

RabbitMQ in PHP

RabbitMQ è un broker che utilizza AMQP 0-9-1. In PHP, il client di riferimento è php-amqplib/php-amqplib (scritto in puro PHP) oppure ext-amqp, basato su C. Questa lezione utilizza php-amqplib perché funziona ovunque sia disponibile Composer.

Il modello AMQP di base ha tre attori: gli exchange ricevono i messaggi, i binding li instradano in base alla chiave e le code li conservano per i consumer. Padroneggi questo modello e il resto sarà solo un dettaglio.

Installazione del client

Aggiunga la libreria con Composer. Sono necessarie le estensioni sockets e bcmath, entrambe comuni nelle build CLI di PHP.

composer require php-amqplib/php-amqplib
# Connection target, e.g. amqp://guest:guest@localhost:5672/

Il modello exchange/queue/binding

I produttori pubblicano su un exchange, mai direttamente su una coda. Il tipo di exchange determina l'instradamento:

  • direct: corrispondenza esatta della routing key.
  • topic: modelli con caratteri jolly come order.*.eu.
  • fanout: trasmissione a tutte le code associate.
  • headers: corrispondenza basata sugli attributi degli header.

Un binding collega una coda a un exchange tramite un modello di instradamento. Disaccoppiare i produttori dalla topologia delle code è l'intero scopo del livello exchange.

Connessione e dichiarazione

Apra una connessione, ottenga un canale e dichiari la topologia. durable: true fa sì che l'exchange/la coda sopravviva al riavvio del broker. Le dichiarazioni sono idempotenti: dichiarare un'entità esistente con argomenti corrispondenti non produce alcun effetto.

<?php
require 'vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;

$conn = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$ch = $conn->channel();

$ch->exchange_declare('orders', 'topic', false, true, false);
$ch->queue_declare('orders.email', false, true, false, false);
$ch->queue_bind('orders.email', 'orders', 'order.created');

echo "Topology ready\n";
$ch->close();
$conn->close();

Pubblicazione di un messaggio

Inserisca il corpo in un AMQPMessage. Imposti delivery_mode = 2 per rendere il messaggio persistente: è la combinazione di una coda durevole e di un messaggio persistente a sopravvivere a un riavvio; una sola delle due caratteristiche non basta.

<?php
require 'vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

$conn = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$ch = $conn->channel();

$payload = json_encode(['orderId' => 42, 'total' => 19.90]);
$msg = new AMQPMessage($payload, [
    'content_type'  => 'application/json',
    'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT,
    'message_id'    => bin2hex(random_bytes(8)),
]);

$ch->basic_publish($msg, 'orders', 'order.created');
echo "Published\n";
$ch->close();
$conn->close();

Consumo con ack manuale

Registri una callback con basic_consume. Passi no_ack = false per gestire manualmente l'acknowledgement. Esegua l'ack solo dopo che l'elaborazione è riuscita; in caso di errore, basic_nack con requeue consente a RabbitMQ di riconsegnare il messaggio.

<?php
require 'vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;

$conn = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$ch = $conn->channel();
$ch->basic_qos(null, 10, null); // prefetch 10

$callback = function ($msg) {
    $data = json_decode($msg->getBody(), true);
    try {
        // ... do work ...
        $msg->ack();
    } catch (\Throwable $e) {
        $msg->nack(true); // requeue
    }
};

$ch->basic_consume('orders.email', '', false, false, false, false, $callback);
while ($ch->is_consuming()) {
    $ch->wait();
}

Prefetch e distribuzione equa

Per impostazione predefinita, RabbitMQ distribuisce i messaggi ai consumer in modo round-robin, senza considerare quanto ciascuno sia occupato: un consumer lento accumula lavoro. basic_qos(null, prefetch, null) limita il numero di messaggi non confermati che un consumer può mantenere.

Imposti prefetch su un numero basso (ad es. 1–10) per attività pesanti e non uniformi, in modo che il broker invii nuovo lavoro solo ai consumer che hanno capacità disponibile. Questa è la distribuzione equa.

Conferme del publisher

basic_publish restituisce immediatamente il controllo e non indica se il broker ha accettato il messaggio. Per garantire la pubblicazione, abiliti le conferme del publisher: il broker invia un ack quando il messaggio è stato salvato o instradato in modo sicuro.

<?php
require 'vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

$conn = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$ch = $conn->channel();
$ch->confirm_select(); // enable confirms on this channel

$ch->set_ack_handler(fn($m) => print("confirmed\n"));
$ch->set_nack_handler(fn($m) => print("REJECTED\n"));

$ch->basic_publish(new AMQPMessage('hi'), 'orders', 'order.created');
$ch->wait_for_pending_acks(5.0); // block until confirmed or timeout

Dead lettering

Configuri l'argomento x-dead-letter-exchange di una coda affinché i messaggi rifiutati (nack senza requeue) o scaduti vengano instradati verso un DLX. Combini questa configurazione con x-delivery-limit sulle code quorum per limitare automaticamente i tentativi.

<?php
use PhpAmqpLib\Wire\AMQPTable;

$args = new AMQPTable([
    'x-dead-letter-exchange'    => 'orders.dlx',
    'x-dead-letter-routing-key' => 'order.failed',
    'x-message-ttl'             => 60000, // ms before expiry
]);
// false=passive, true=durable, false=exclusive, false=autodelete, args
$ch->queue_declare('orders.email', false, true, false, false, false, $args);
$ch->queue_declare('orders.dead', false, true, false, false);
$ch->queue_bind('orders.dead', 'orders.dlx', 'order.failed');

Esecuzione dei worker in produzione

Alcune regole operative maturate sul campo per i worker RabbitMQ in PHP:

  • Esegua i consumer come processi CLI di lunga durata sotto un supervisore (systemd / Supervisor) che li riavvii alla loro terminazione.
  • PHP può perdere memoria nel tempo: riavvii il worker dopo N messaggi o al superamento di una soglia di memoria.
  • Invii heartbeat AMQP e gestisca SIGTERM per un arresto controllato (completi il messaggio in corso, quindi si fermi).
  • Utilizzi le code quorum per l'HA invece delle code mirrorate legacy.

Arresto controllato

I deployment inviano SIGTERM. Un worker ingenuo termina durante l'elaborazione di un messaggio, forzandone la riconsegna. Installi un gestore di segnali che imposti un flag; completi il messaggio corrente, ne esegua l'ack, quindi esca pulitamente dal ciclo di consumo. pcntl_async_signals(true) consente a PHP di consegnare il segnale tra un'attesa AMQP e l'altra.

<?php
pcntl_async_signals(true);
$running = true;
pcntl_signal(SIGTERM, function () use (&$running) {
    $running = false; // stop after the current message
    echo "SIGTERM: draining...\n";
});

while ($running && $ch->is_consuming()) {
    try {
        $ch->wait(null, false, 5); // wakes for signals
    } catch (\PhpAmqpLib\Exception\AMQPTimeoutException $e) {
        // idle tick - loop and re-check $running
    }
}
$ch->close();
echo "Stopped cleanly\n";

Verifica rapida

Sopravvivere al riavvio di un broker.

Riepilogo

Ora è in grado di creare una pipeline RabbitMQ reale in PHP:

  • Pubblichi su un exchange; instradi tramite i binding verso le code.
  • La combinazione coda durevole + messaggio persistente sopravvive ai riavvii.
  • Consumi con ack manuale e regoli il prefetch di basic_qos per una distribuzione equa.
  • Utilizzi le conferme del publisher per invii garantiti e un DLX per i messaggi non elaborabili.
  • Esegua i worker sotto un supervisore, con heartbeat e arresto controllato.

Successivamente: Kafka, quando serve lo streaming ad alto throughput invece dell'accodamento delle attività.

Gratis per iniziare

Impara PHP con un tutor IA — gratis

Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.

Corsi
49
Lezioni
195

Domande Frequenti

La lezione «Utilizzare RabbitMQ in PHP» è gratuita?

Sì — il testo completo di «Utilizzare RabbitMQ in PHP» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso PHP Academy, passa a CoddyKit PRO. Il corso PHP Academy include 4 lezioni in totale.

Cosa imparerò in «Utilizzare RabbitMQ in PHP»?

Pubblicate e consumate messaggi con RabbitMQ. Eserciti PHP Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare PHP Academy?

Non è richiesta alcuna esperienza precedente. PHP Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «Utilizzare RabbitMQ in PHP»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione PHP Academy?

Sì. Ogni lezione PHP Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Perché usare la messaggistica asincrona
  2. Utilizzare RabbitMQ in PHP
  3. Apache Kafka con PHP
  4. Creare flussi di lavoro basati sugli eventi
← Torna a PHP Academy