如何将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管理进程,能实现开机自启、异常自动重启,步骤如下:
- 创建systemd服务文件:
sudo nano /etc/systemd/system/stomp-consumer.service
- 写入以下内容(根据实际路径修改):
[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指定日志输出位置,也可以用脚本内部的日志
- 启用并启动服务:
sudo systemctl daemon-reload sudo systemctl enable stomp-consumer.service sudo systemctl start stomp-consumer.service
- 常用命令:
# 查看服务状态 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
相关产品推荐
相关产品推荐

