You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将PHP Stomp消息消费脚本作为Ubuntu后台进程运行?

解决方案

一、先优化脚本稳定性(解决连接丢失、CPU空转问题)

原脚本存在两个核心问题:

  • while($con)无法检测连接是否真的存活,一旦TCP连接异常断开,脚本会陷入空循环
  • hasFrame()是非阻塞调用,循环会持续占用100% CPU

修改后的脚本添加重连逻辑、异常捕获、阻塞读取,同时增加日志记录便于排查:

<?php
$server = "tcp://url:61618";
$user = "";
$password = "";
$channel = "channel";
$logFile = 'consumer.log';
$outputFile = 'file.txt';
$clientId = 'tsr';
$subscriptionName = 'tsr';

// 日志记录函数
function logMessage($msg) {
    global $logFile;
    file_put_contents($logFile, date('Y-m-d H:i:s') . " - " . $msg . PHP_EOL, FILE_APPEND);
}

// 连接与订阅逻辑封装
function connectAndSubscribe(&$con, $server, $user, $password, $clientId, $channel, $subscriptionName) {
    try {
        $con = new Stomp($server, $user, $password, ['client-id' => $clientId]);
        $con->subscribe("/topic/" . $channel, ['activemq.subscriptionName' => $subscriptionName]);
        logMessage("成功连接并订阅Topic: /topic/$channel");
        return true;
    } catch (Exception $e) {
        logMessage("连接/订阅失败: " . $e->getMessage());
        return false;
    }
}

// 初始化连接
$con = null;
while (!connectAndSubscribe($con, $server, $user, $password, $clientId, $channel, $subscriptionName)) {
    logMessage("重试连接...等待5秒");
    sleep(5);
}

while (true) {
    try {
        // 使用阻塞读取(第二个参数设为true),避免CPU空转
        $msg = $con->readFrame(true);
        
        if ($msg) {
            $events = json_decode($msg->body);
            if ($events) {
                foreach ($events as $event) {
                    $response = print_r($event, true);
                    file_put_contents($outputFile, $response . PHP_EOL, FILE_APPEND);
                }
            } else {
                logMessage("消息体JSON解析失败: " . $msg->body);
            }
            $con->ack($msg);
        }
    } catch (Exception $e) {
        logMessage("消费过程出错: " . $e->getMessage() . ",尝试重连");
        // 销毁旧连接
        unset($con);
        // 循环重连直到成功
        while (!connectAndSubscribe($con, $server, $user, $password, $clientId, $channel, $subscriptionName)) {
            logMessage("重试连接...等待5秒");
            sleep(5);
        }
    }
}

// 以下代码理论上不会执行,除非主动退出
$con->disconnect();
?>

关键改动说明:

  • 封装连接订阅逻辑,支持自动重连
  • 使用readFrame(true)阻塞读取消息,避免CPU空转
  • 添加异常捕获,连接或消费出错时自动重试
  • 增加日志文件consumer.log,便于排查问题

二、后台运行方案

临时方案:nohup + &

如果只是临时后台运行,执行以下命令:

sudo nohup php ./myfile.php > /dev/null 2>&1 &
  • nohup让脚本脱离终端运行,即使SSH断开也不会终止
  • > /dev/null 2>&1将标准输出和错误输出重定向到空设备,避免生成nohup.out文件
  • 可以用ps aux | grep myfile.php查看进程状态,kill <PID>终止进程

长期稳定方案:systemd服务(推荐)

Ubuntu下用systemd管理进程,能实现开机自启、异常自动重启,步骤如下:

  1. 创建systemd服务文件:
sudo nano /etc/systemd/system/stomp-consumer.service
  1. 写入以下内容(根据实际路径修改):
[Unit]
Description=ActiveMQ Stomp Consumer Service
After=network.target activemq.service

[Service]
User=root
WorkingDirectory=/path/to/your/script/dir
ExecStart=/usr/bin/php ./myfile.php
Restart=always
RestartSec=5
StandardOutput=append:/var/log/stomp-consumer.log
StandardError=append:/var/log/stomp-consumer.log

[Install]
WantedBy=multi-user.target
  • WorkingDirectory是脚本所在目录的绝对路径
  • Restart=always配置进程异常退出后自动重启
  • StandardOutput/StandardError指定日志输出位置,也可以用脚本内部的日志
  1. 启用并启动服务:
sudo systemctl daemon-reload
sudo systemctl enable stomp-consumer.service
sudo systemctl start stomp-consumer.service
  1. 常用命令:
# 查看服务状态
sudo systemctl status stomp-consumer.service
# 查看日志
sudo tail -f /var/log/stomp-consumer.log
# 重启服务
sudo systemctl restart stomp-consumer.service
# 停止服务
sudo systemctl stop stomp-consumer.service

三、额外注意事项

  • 确保file.txt和日志文件有足够的写入权限,避免因权限问题导致脚本异常
  • ActiveMQ的持久订阅需要client-id和subscriptionName保持一致,脚本中已经配置,无需改动
  • 如果使用SSL连接(比如ssl://url:61617),确保PECL Stomp的OpenSSL支持正常,无需额外配置

内容的提问来源于stack exchange,提问作者RodneyUK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 17:53:11