May
11
2024
php实现 master-worker 守护多进程模式的实例代码
作者:
绝缘体.. 发布:
2024-05-11 06:58 分类:
未分类 阅读:
抢沙发
php实现 master-worker 守护多进程模式的实例代码。
<?php
/**
* Class Worker
* php实现 master-worker 守护多进程模式的实例代码
* kill 主进程,自动杀掉子进程
* 子进程意外终止将会被守护进程重新创建
* @link https://www.phpernote.com/
* @author www.phpernote.com
* @to do 判断进程是否已经启动,不允许重复启动
*/
class Worker {
private static $process_title = 'phpernote.com';
public static $count = 2;
public static $job_iterations = 10;
private static $child_pids = []; // 存储所有子进程的PID
public static function run(): void {
// 注册信号处理函数
pcntl_signal(SIGTERM, [__CLASS__, 'handleSignal']);
pcntl_signal(SIGINT, [__CLASS__, 'handleSignal']);
try {
static::runMaster();
static::monitorWorkerProcess();
} catch (Exception $e) {
echo "发生错误: " . $e->getMessage() . "\r\n";
}
}
/**
* 开启主进程
* @throws Exception
*/
public static function runMaster(): void {
umask(0);
$pid = pcntl_fork();
if ($pid > 0) {
echo "主进程进程 $pid\r\n";
exit;
} else if ($pid == 0) {
if (-1 === posix_setsid()) {
throw new Exception('setsid fail');
}
for ($i = 0; $i < self::$count; $i++) {
$child_pid = static::runWorker();
self::$child_pids[] = $child_pid; // 存储子进程PID
}
cli_set_process_title(self::$process_title . 'master_process');
} else {
throw new Exception('创建主进程失败');
}
}
/**
* 开启子进程
* @throws Exception
*/
public static function runWorker() {
umask(0);
$pid = pcntl_fork();
if ($pid > 0) {
echo "创建子进程 $pid \r\n";
return $pid; // 返回子进程PID给主进程存储
} else if ($pid == 0) {
if (-1 === posix_setsid()) {
throw new Exception('setsid fail');
}
cli_set_process_title(self::$process_title . 'worker_process');
try {
self::doJob();
} catch (Exception $e) {
echo "Worker 进程发生错误: " . $e->getMessage() . "\r\n";
}
exit; // 确保Worker完成任务后退出
} else {
throw new Exception('创建子进程失败');
}
}
/**
* 监控worker进程
* @throws Exception
*/
public static function monitorWorkerProcess(): void {
while (true) {
$pid = pcntl_wait($status);
if ($pid == -1) {
if ($errno = pcntl_wexitstatus($status)) {
echo "子进程异常退出,错误码: $errno\r\n";
}
break;
} else {
echo "子进程 $pid 退出,正在重新创建...\r\n";
static::runWorker();
}
}
}
/**
* 业务逻辑
*/
public static function doJob(): void {
for ($i = 0; $i < self::$job_iterations; $i++) {
sleep(3);
echo '进程:' . posix_getpid() . ' ' . date('Y-m-d H:i:s') . ' 输出' . "\r\n";
}
echo "Worker 任务执行完毕\r\n";
}
/**
* 信号处理函数
* @param $signal
* @return void
*/
public static function handleSignal($signal): void {
echo "接收到信号 " . $signal . ",开始清理...\r\n";
foreach (self::$child_pids as $pid) {
posix_kill($pid, SIGTERM); // 尝试优雅地终止子进程
posix_kill($pid, SIGKILL); // 如果优雅终止失败,则强制终止
}
exit; // 清理完成后,终止主进程
}
}
Worker::run();
经过 chatGPT 优化后的代码如下:
<?php
/**
* Class Worker
* php实现 master-worker 守护多进程模式的实例代码
* kill 主进程,自动杀掉子进程
* 子进程意外终止将会被守护进程重新创建
* @link https://www.phpernote.com/
* @author www.phpernote.com
* @to do 判断进程是否已经启动,不允许重复启动
*/
class Worker {
private static $process_title_master = 'phpernote_master';
private static $process_title_child = 'phpernote_child';
public static $count = 2;
public static $job_iterations = 10;
private static $child_pids = []; // 存储所有子进程的PID
public static function run(): void {
// 注册信号处理函数
pcntl_signal(SIGTERM, [__CLASS__, 'handleSignal']);
pcntl_signal(SIGINT, [__CLASS__, 'handleSignal']);
try {
static::runMaster();
} catch (Exception $e) {
echo "发生错误: " . $e->getMessage() . "\r\n";
}
}
/**
* 开启主进程
* @throws Exception
*/
public static function runMaster(): void {
umask(0);
$pid = pcntl_fork();
if ($pid > 0) {
echo "主进程进程 $pid\r\n";
cli_set_process_title(self::$process_title_master);
static::runWorkers();
static::monitorWorkerProcess();
} else if ($pid == 0) {
if (-1 === posix_setsid()) {
throw new Exception('setsid fail');
}
cli_set_process_title(self::$process_title_child);
} else {
throw new Exception('创建主进程失败');
}
}
/**
* 开启子进程
* @throws Exception
*/
public static function runWorkers(): void {
for ($i = 0; $i < self::$count; $i++) {
$child_pid = static::runWorker();
self::$child_pids[] = $child_pid; // 存储子进程PID
}
}
/**
* 开启单个子进程
* @throws Exception
*/
public static function runWorker() {
umask(0);
$pid = pcntl_fork();
if ($pid > 0) {
echo "创建子进程 $pid \r\n";
return $pid; // 返回子进程PID给主进程存储
} else if ($pid == 0) {
if (-1 === posix_setsid()) {
throw new Exception('setsid fail');
}
cli_set_process_title(self::$process_title_child);
try {
self::doJob();
} catch (Exception $e) {
echo "Worker 进程发生错误: " . $e->getMessage() . "\r\n";
}
exit; // 确保Worker完成任务后退出
} else {
throw new Exception('创建子进程失败');
}
}
/**
* 监控worker进程
* @throws Exception
*/
public static function monitorWorkerProcess(): void {
while (true) {
$pid = pcntl_wait($status);
if ($pid == -1) {
if ($errno = pcntl_wexitstatus($status)) {
echo "子进程异常退出,错误码: $errno\r\n";
}
break;
} else {
echo "子进程 $pid 退出,正在重新创建...\r\n";
// 从数组中删除已退出的子进程 PID
$index = array_search($pid, self::$child_pids);
if ($index !== false) {
unset(self::$child_pids[$index]);
}
static::runWorker();
}
}
}
/**
* 业务逻辑
*/
public static function doJob(): void {
for ($i = 0; $i < self::$job_iterations; $i++) {
sleep(3);
echo '进程:' . posix_getpid() . ' ' . date('Y-m-d H:i:s') . ' 输出' . "\r\n";
}
echo "Worker 任务执行完毕\r\n";
}
/**
* 信号处理函数
* @param $signal
* @return void
*/
public static function handleSignal($signal): void {
echo "接收到信号 " . $signal . ",开始清理...\r\n";
foreach (self::$child_pids as $pid) {
posix_kill($pid, SIGTERM); // 尝试优雅地终止子进程
// 一段时间后再尝试强制终止
pcntl_alarm(5); // 5秒后发送SIGKILL
}
}
}
Worker::run();
微信扫一扫,打赏作者吧~