RabbitMQ primary package / based on a development php-amqplib

RabbitMQ implements AMQP protocol (Advanced Message Queuing Protocol).

Based on my understanding of the RabbitMQ:

    Structure consisting essentially of : publisher (producer), exchange (switch), queue (message queue), consumer (customer)

    Introduction respective data structures:

        Publisher (Manufacturer): as a producer of the message, generating the message stored in the message queue, the production process is the manufacturer shipment of goods.

        exchange (switch) : dispatcher message, the message first passes through it, the dispatcher by type of goods will be put in different vending machines.

        Queue (Message Queue) : the message repository, vending machines.

        consumer (consumer) : Consumers message, remove the message from the storage warehouse, the process of consumption is people buy from vending machines.

    Common exchange types Topic, headers, Direct, fanout .

    A supplementary concept:

        Message acknowledgment mechanism : that is, the two sides interact sender of the message will be sent out after the message, the recipient needs to be fed back to the consumer the message has been received (the message does not matter where the processing is complete), and interactive amqp parties also need this mechanism to ensure indeed received the message ( so the recipient after receiving the message requires acknowledgment packet returns ack, since the two-way interaction is no longer always be meaningless duplicate acknowledgment, i.e. no longer consider network delay caused where the sender receives no the ack packet ), to ensure that the message has indeed been received by the recipient, the message can be removed warehouse. Unfortunately, when playing a parable, that you have to paid, vending machine before being really the merchandise sold.

        The default exchange: When a producer is not specified exchange, the message will be sent to the default ligand exchange, the allocation rule: default exchange will send a message to the queue in queue according to a specified queue.

(MQ I conducted on the production and consumption of the package `` but did not achieve high availability, allows users to shift attention to the business logic processing)

Here is the code, directory structure:

/ Mq / abs abstraction layer

/ Mq / obj embodied layer

/ Mq / config configuration

/ Mq / web application layer (demo)

 

/mq/abs/MqclientObject.php

<?php
namespace mq\abs;

use \PhpAmqpLib\Connection as MQC;
use \PhpAmqpLib\Exception\AMQPHeartbeatMissedException;

abstract class MqClientObject
{

    public $channel;

    private static $connect;

    private static $config;

    private static $lastConnectTime;

    public function __construct(array $config)
    {
        if(!(self::$connect instanceof MQC\AMQPStreamConnection)) {
            self::connect($config);
        }
        if(!self::$config) {
            self::$config = $config;
        }
        $this->channel = self::$connect->channel();
    }

    private static function connect(array $config)
    {
        self::$connect = new MQC\AMQPStreamConnection(
            $config['host'],
            $config['port'],
            $config['user'],
            $config['password'],
            isset($config['vhost']) && !empty($config['vhost']) ? $config['vhost'] : '/'
        );
        self::$lastConnectTime = time();
    }

    public static function close()
    {
        try{
            self::$connect->close();
            self::$connect = null;
            self::$config = null;
        } catch (\Exception $ex) {
            return false;
        }
        return true;
    }

    public function createTempQueue()
    {
        list($queue, ) = $this->channel->queue_declare("", false, false, true, false);
        return $queue;
    }


    public function ping()
    {
        try{
            self::$connect->checkHeartBeat();
        } catch (AMQPHeartbeatMissedException $MQheartEx) {
            return false;
        } catch(\Exception $ex) {
            //todo log
            exit(0);
        }
        return true;
    }

    public function reConnect()
    {
        self::connect(self::$config);
    }

}

/mq/abs/MqconsumerObject.php

<?php
namespace mq\abs;

abstract class MqConsumerObject extends MqClientObject
{

    public $queue;

    private $blocking = true;

    private $qos = true;

    private $ack = false;

    private $qosCount = 1;

    public function setQueue($queue)
    {
        $this->queue = $queue;
        return $this;
    }

    public function disableAck()
    {
        $this->ack = true;
    }

    public function disablePos()
    {
        $this->qos = false;
    }

    public function setQosCount($count)
    {
        $this->qosCount = $count;
    }

    public function disableBlocking()
    {
        $this->blocking = false;
    }

    //默认的消费方式
    public function consume($failClose = false)
    {
        if($this->qos) {
            $this->channel->basic_qos(null, $this->qosCount, null);
        }
        $this->channel->basic_consume(
            $this->queue,
            '',
            false,
            $this->ack,
            false,
            false,
            [$this, 'call']
        );

        while(count($this->channel->callbacks)) {
            $this->channel->wait();
            if(!$this->blocking) {
                $this->channel->close();
            }
        }
    }


    //回调函数
    public function call($event)
    {
        $message = $event->body;
        $channel = $event->delivery_info['channel'];
        if($this->run($message)) {
            $channel->basic_ack($event->delivery_info['delivery_tag']);
        }
    }


    public function closeChannel()
    {
        try{
            $this->channel->close();
            $this->channel = null;
        } catch (\Exception $ex) {
            return false;
        }
        return true;
    }

    //业务处理
    public abstract function run($message);

    public function __destruct()
    {
        if($this->channel != null) {
            $this->closeChannel();
        }
    }
}

/mq/abs/MqPublisherObject.php

<?php
namespace mq\abs;


abstract class MqPublisherObject extends MqClientObject
{

     public $exchange;

     public $bindKey;

     public $queue;

     public function setExchange($exchange)
     {
         $this->exchange = $exchange;
         return $this;
     }

     public function setBindKey($bindKey)
     {
         $this->bindKey = $bindKey;
         return $this;
     }

     public function setQueue($queue)
     {
         $this->queue = $queue;
         return $this;
     }

     public abstract function bind();

     public abstract function publish($message, $config = null);

}

/mq/config/mq_config

<?php

define('MQ_CONFIG', [
    'host' => '127.0.0.1',
    'port' => 5672,
    'user' => 'dora',
    'password' => 'hopeforyou',
    'vhost' => '/dora'
]);

/mq/obj/DirectPublisherObject.php

<?php
namespace mq\obj;

use \mq\abs as MA;
use \PhpAmqpLib\Message as PM;

class DirectPublisherObject extends MA\MqPublisherObject
{

    public function bind()
    {
        $this->channel->queue_bind($this->queue, $this->exchange, $this->bindKey);
    }

    public function publish($message, $config = null)
    {
        $objMessage = new PM\AMQPMessage($message);
        $this->channel->basic_publish($objMessage, $this->exchange, $this->bindKey);
    }
}

/mq/obj/FanoutPublisherObject.php

<?php
namespace mq\obj;

use \mq\abs as MA;
use \PhpAmqpLib\Message as PM;

class FanoutPublisherObject extends MA\MqPublisherObject
{

    public function bind()
    {
        $this->channel->queue_bind($this->queue, $this->exchange);
    }

    public function publish($message, $config = null)
    {
        //暂不支持$config配置
        $objMessage = new PM\AMQPMessage($message);
        $this->channel->basic_publish($objMessage, $this->exchange);
    }
}

/mq/obj/TopicsPublisherObject.php

<?php
namespace mq\obj;

use \mq\abs as MA;
use \PhpAmqpLib\Message as PM;

class TopicsPublisherObject extends MA\MqPublisherObject
{

    public function bind()
    {
        $this->channel->bind_queue($this->queue, $this->exchange, $this->bindKey);
    }

    public function publish($message, $config = null)
    {
        $objMessage = new PM\AMQPMessage($message);
        $this->channel->basic_publish($objMessage, $this->exchange, $this->bindKey);
    }
}

/mq/obj/PayCallbackConsumer.php

<?php
namespace mq\obj;

use mq\abs\MqConsumerObject;

class PayCallbackConsumer extends MqConsumerObject
{

    public function run($message)
    {
        //todo 业务逻辑代码
        //消费者消费一次完毕后就不再消费
//        $this->disableBlocking();
        //return true 代表消息处理完毕
        //return false 代表消息处理异常,不正真消费
    }

}

/mq/web/index.php test code

<?php
define('APP_PATH', dirname(__DIR__));

require APP_PATH.'/vendor/autoload.php';    //注册自动加载函数列表
require APP_PATH.'/config/mq_config.php';   //mq注册常量

//use \mq\obj as MO;


//将$queue绑定到exchange dora.fanout上
//$objMq = new MO\FanoutPublisherObject(MQ_CONFIG);
////交换机绑定队列
////$queue = 'dora.hope.for.you';
////$objMq->setExchange('dora.fanout')->setQueue($queue)->bind();
////向交换机发送消息
//$objMq->setExchange('dora.fanout');
//$objMq->publish('hope for you!');

//将$queue绑定到exchange dora.direct上
//$objMq = new MO\DirectPublisherObject(MQ_CONFIG);
//$bindKey = 'hope';
//交换机绑定队列
//$queue = 'dora.direct.hope.for';
//$objMq->setExchange('dora.direct')->setBindKey($bindKey)->setQueue($queue)->bind();
//向交换机发送消息
//$objMq->setExchange('dora.direct')->setBindKey($bindKey);
//$objMq->publish('hope for you!');

//将$queue绑定到exchange dora.topic上
//$objMq = new MO\DirectPublisherObject(MQ_CONFIG);
//$bindKey = 'hope.for';
//交换机绑定队列
//$queue = 'dora.topic.hope.for';
//$objMq->setExchange('dora.topic')->setBindKey($bindKey)->setQueue($queue)->bind();
//向交换机发送消息
//$objMq->setExchange('dora.topic')->setBindKey($bindKey);
//$objMq->publish('hope for you!');

//消费队列
//$objConsumer = new MO\PayCallbackConsumer(MQ_CONFIG);
//$queue = 'dora.hope.for.you';
//$objConsumer->setQueue($queue)->consume();

The user when a message is uploaded to the message queue, only need to be concerned about the switch used in exchange, routing route. (Actual item and does not create a queue (except temporary queue) by the code or switch);

User queue in the consumer, only need to inherit MqconsumerObject class and implements the run method, to process the message;

 

reference:

RabbitMQ + PHP Tutorial

Published 31 original articles · won praise 3 · views 10000 +

Guess you like

Origin blog.csdn.net/qq_36557960/article/details/100052639