Fastadmin 使用RabbitMQ队列

在Fastadmin 简单使用RabbitMQ队列实现消息的收发

目录

在php中进行消息的收发

安装依赖库

安装php-amqplib

安装ext-sockets扩展

手动开启

小皮面板

重新安装依赖库

配置 RabbitMQ 连接信息

封装 RabbitMQ 基础类

实现生产者(发送消息)

实现消费者(处理消息)

步骤 1:创建消费者命令

步骤 2:注册命令

步骤 3:启动消费者

测试验证

注意事项

总结


在php中进行消息的收发

在 PHP 中操作 RabbitMQ 需要借助php-amqplib扩展,以下是通过 PHP 代码实现消息收发(生产者和消费者)的详细步骤:

安装依赖库

安装php-amqplib

使用 Composer 安装php-amqplib(RabbitMQ 的 PHP 客户端库):

composer require php-amqplib/php-amqplib

问题:最高只能安装到2.8版本,使用的rabbitmq链接代码较为落后。

安装提示:Cannot use php-amqplib/php-amqplib's latest version v3.7.3 as it requires ext-sockets * which is missing from your platform.

解决问题:

这个错误提示说明:php-amqplib v3.7.3 依赖 PHP 的 ext-sockets 扩展,但你的 PHP 环境中没有启用该扩展,导致安装失败。

安装ext-sockets扩展
手动开启

Windows 下的 PHP 通常已预编译 sockets 扩展,只需手动启用:

找到 PHP 的配置文件 php.ini:

打开 php.ini,搜索 extension=sockets:

若找到该行且前面有 ;(注释),去掉 ; 即可(如 ;extension=sockets → extension=sockets)。

若未找到,直接添加一行:extension=sockets(注意:PHP 7.0+ 通常不需要加 php_ 前缀,旧版本可能是 extension=php_sockets.dll)。

保存文件,重启 Web 服务器(如 Apache、Nginx)或 PHP 进程。

小皮面板

在网站列表,找到相应网站,选择php扩展,找到sockets打开,然后重启服务即可。

扩展如下:

重新安装依赖库

先卸载安装的2.8版本 php-amqplib/php-amqplib

composer remove php-amqplib/php-amqplib

这次安装的版本为3.7,如下:

配置 RabbitMQ 连接信息

在application/config.php文件下新增rabbitmq配置文件,存放连接参数:

// +----------------------------------------------------------------------
// | Rabbit设置
// +----------------------------------------------------------------------
'rabbit'                   => [
    // RabbitMQ主机
    'host'      => '127.0.0.1',
    // 端口
    'port'      => 5672,
    // 用户名(默认guest,仅本地访问)
    'user'      => 'guest',
    // 密码
    'password'  => 'guest',
    // 虚拟主机
    'vhost'     => '/',
    // 心跳检测时间(秒)
    'heartbeat' => 60,
    // 默认队列名称
    'queue'     => [
        'default' => 'fastadmin_default_queue',
    ]
],

封装 RabbitMQ 基础类

创建基础工具类处理连接、通道和队列声明,减少重复代码。

在application/common/library目录下新建RabbitMQ.php:

<?php
namespace app\common\library;

use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use think\Config;

class RabbitMQ
{
    protected $connection;  // 连接对象

    protected $channel;     // 通道对象

    protected $config;      // 配置参数

    public function __construct()
    {
        $this->config = Config::get('rabbitmq');
        $this->connect();
    }

    // 建立连接
    protected function connect()
    {
        try {
            $this->connection = new AMQPStreamConnection(
                $this->config['host'],
                $this->config['port'],
                $this->config['user'],
                $this->config['password'],
                $this->config['vhost'],
                false,
                'AMQPLAIN',
                null,
                'en_US',
                $this->config['heartbeat'],
                null
            );
            $this->channel = $this->connection->channel();
        } catch (\Exception $e) {
            throw new \Exception("RabbitMQ连接失败:" . $e->getMessage());
        }
    }

    // 声明队列(确保队列存在)
    public function declareQueue($queueName = null)
    {
        $queue = $queueName ?: $this->config['queue']['default'];
        // 参数:队列名、是否持久化、是否排他、是否自动删除、其他参数
        $this->channel->queue_declare($queue, false, true, false, false);
        return $queue;
    }

    // 发送消息到队列
    public function send($data, $queueName = null)
    {
        $queue = $this->declareQueue($queueName);
        $message = new AMQPMessage(
            json_encode($data, JSON_UNESCAPED_UNICODE),
            ['delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT]  // 消息持久化
        );
        $this->channel->basic_publish($message, '', $queue);
    }

    // 消费消息(回调处理)
    public function consume($callback, $queueName = null)
    {
        $queue = $this->declareQueue($queueName);
        // 参数:队列名、消费者标签、是否自动确认、是否排他、是否本地、是否阻塞、回调函数
        $this->channel->basic_consume($queue, '', false, false, false, false, $callback);

        // 循环监听消息
        while ($this->channel->is_consuming()) {
            $this->channel->wait();
        }
    }

    // 关闭连接
    public function close()
    {
        if ($this->channel) {
            $this->channel->close();
        }
        if ($this->connection) {
            $this->connection->close();
        }
    }

    // 析构函数自动关闭连接
    public function __destruct()
    {
        $this->close();
    }
}

实现生产者(发送消息)

在业务逻辑中调用RabbitMQ类发送消息到队列(例如控制器中):

在api/Demo.php中新增sendMessage方法,如下:

// 示例:发送消息到队列
public function sendMessage()
{
    try {
        $rabbitMQ = new RabbitMQ();
        // 发送的数据(数组格式)
        $data = [
            'id' => 123,
            'content' => '这是一条测试消息',
            'time' => date('Y-m-d H:i:s')
        ];
        // 发送到默认队列(也可指定队列名:$rabbitMQ->send($data, 'custom_queue'))
        $rabbitMQ->send($data);
        return '消息发送成功';
    } catch (\Exception $e) {
        return '发送失败:' . $e->getMessage();
    }
}

实现消费者(处理消息)

消费者需持续运行监听队列,建议通过命令行脚本实现(FastAdmin 基于 ThinkPHP 的命令行机制)。

步骤 1:创建消费者命令

在application/common/command目录下新建RabbitMQConsumer.php:

<?php
namespace app\common\command;

use app\common\library\RabbitMQ;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\Log;

class RabbitMQConsumer extends Command
{
    // 配置命令
    protected function configure()
    {
        $this->setName('rabbitmq:consumer')  // 命令名:php think rabbitmq:consumer
        ->setDescription('RabbitMQ消费者,处理队列消息');
    }

    // 执行命令
    protected function execute(Input $input, Output $output)
    {
        $output->writeln('消费者启动成功,开始监听队列...');
        try {
            $rabbitMQ = new RabbitMQ();
            // 消息处理回调函数
            $callback = function ($msg) use ($output) {
                $output->writeln('收到消息:' . $msg->body);
                // 解析消息(原发送的数组)
                $data = json_decode($msg->body, true);
                if (empty($data)) {
                    $output->writeln('消息格式错误');
                    $msg->nack(false, false);  // 拒绝消息,不重新入队
                    return;
                }

                // 业务处理逻辑(例如:发送邮件、生成报表等)
                try {
                    // TODO: 这里写具体的处理代码
                    $output->writeln('处理成功:' . $data['id']);
                    $msg->ack();  // 确认消息已处理(从队列删除)
                } catch (\Exception $e) {
                    Log::error('消息处理失败:' . $e->getMessage());
                    $msg->nack(false, true);  // 处理失败,重新入队(可限制重试次数)
                }
            };

            // 监听默认队列(可指定队列名:$rabbitMQ->consume($callback, 'custom_queue'))
            $rabbitMQ->consume($callback);
        } catch (\Exception $e) {
            $output->writeln('消费者异常:' . $e->getMessage());
            Log::error('消费者异常:' . $e->getMessage());
        }
    }
}

步骤 2:注册命令

在application/command.php中注册命令:

return [
    'app\admin\command\Crud',
    'app\admin\command\Menu',
    'app\admin\command\Install',
    'app\admin\command\Min',
    'app\admin\command\Addon',
    'app\admin\command\Api',
    'app\common\command\RabbitMQConsumer', # 消费者
];
步骤 3:启动消费者

在项目根目录执行命令启动消费者:

php think rabbitmq:consumer

若需在后台运行(生产环境),可结合supervisor管理进程(确保进程意外退出后自动重启)。

效果如下:

测试验证

访问http://你的域名/api/demo/sendMessage发送测试消息。

查看消费者控制台输出,应显示 “收到消息” 和处理结果。

请求效果:

处理效果:

若处理失败,消息会重新入队(根据nack参数配置)。

注意事项

消息持久化:队列和消息均需设置持久化(已在基础类中配置),避免 RabbitMQ 重启后消息丢失。

错误处理:消费者需捕获业务异常,通过ack()/nack()控制消息状态,避免死循环。

性能优化:生产环境可根据需求调整消费者数量(多个进程同时消费),或使用交换机(Exchange)分发消息到不同队列。

权限问题:默认guest用户仅允许本地访问,远程连接需创建新用户并授权(通过 RabbitMQ 管理界面:http://ip:15672)。

总结

在Fastadmin 简单使用RabbitMQ队列实现消息的收发

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JSON_L

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值