php – 将proc_open()获取的管道重定向到文件,以获取剩余的进程
比方说,在
PHP中,我有很多单元测试.
说他们需要一些服务才能运行. 理想情况下,我希望我的引导脚本: >启动这项服务 我目前正在使用proc_open()来初始化我的服务,使用管道机制捕获输出,通过检查输出来检查服务是否达到了我需要的状态. 但是在这一点上我很难过 – 如何在脚本的剩余时间内捕获剩余的输出(包括STDERR),同时仍允许我的单元测试运行? 我可以想到一些可能冗长的解决方案,但在花时间调查它们之前,我想知道是否有其他人遇到过这个问题以及他们找到了什么解决方案,如果有的话,而不影响响应. 编辑: 这是我在我的引导脚本(使用新的ServiceRunner)初始化的类的缩减版本,供参考: <?php namespace Tests; class ServiceRunner { /** * @var resource[] */ private $servicePipes; /** * @var resource */ private $serviceProc; /** * @var resource */ private $temp; public function __construct() { // Open my log output buffer $this->temp = fopen('php://temp','r+'); fputs(STDERR,"Launching Service.n"); $this->serviceProc = proc_open('/path/to/service',[ 0 => array("pipe","r"),1 => array("pipe","w"),2 => array("pipe",],$this->servicePipes); // Set the streams to non-blocking,so stream_select() works stream_set_blocking($this->servicePipes[1],false); stream_set_blocking($this->servicePipes[2],false); // Set up array of pipes to select on $readables = [$this->servicePipes[1],$this->servicePipes[2]); while(false !== ($streams = stream_select($read = $readables,$w = [],$e = [],1))) { // Iterate over pipes that can be read from foreach($read as $stream) { // Fetch a line of input,and append to my output buffer if($line = stream_get_line($stream,8192,"n")) { fputs($this->temp,$line."n"); } // Break out of both loops if the service has attained the desired state if(strstr($line,'The Service is Listening' ) !== false) { break 2; } // If the service has closed one of its output pipes,remove them from those we're selecting on if($line === false && feof($stream)) { $readables = array_diff($readables,[$stream]); } } } /* SOLUTION REQUIRED SOLUTION REQUIRED SOLUTION REQUIRED SOLUTION REQUIRED */ /* Set up the pipes to be redirected to $this->temp here */ register_shutdown_function([$this,'shutDown']); } public function shutDown() { fputs(STDERR,"Closing...n"); fclose($this->servicePipes[0]); proc_terminate($this->serviceProc,SIGINT); fclose($this->servicePipes[1]); fclose($this->servicePipes[2]); proc_close($this->serviceProc); fputs(STDERR,"Closed servicen"); $logFile = fopen('log.txt','w'); rewind($this->temp); stream_copy_to_stream($this->temp,$logFile); fclose($this->temp); fclose($logFile); } } 解决方法
假设该服务实现为service.sh shell脚本,其中包含以下内容:
#!/bin/bash - for i in {1..4} ; do printf 'Step %dn' $i printf 'Step Error %dn' $i >&2 sleep 0.7 done printf '%sn' 'The service is listening' for i in {1..4} ; do printf 'Output %dn' $i printf 'Output Error %dn' $i >&2 sleep 0.2 done echo 'Done' 该脚本模拟启动过程,打印指示服务已准备就绪的消息,并在启动后打印一些输出. 由于在读取“服务就绪标记”之前您没有继续进行单元测试,因此我认为没有特殊原因可以异步执行此操作.如果你想在等待服务的同时运行一些进程(更新UI等),我建议使用具有异步功能的扩展(pthreads,ev,event等). 但是,如果异步只做两件事,那么为什么不分叉一个进程呢?该服务可以在父进程中运行,并且可以在子进程中启动单元测试: <?php $cmd = './service.sh'; $desc = [ 1 => [ 'pipe','w' ],2 => [ 'pipe',]; $proc = proc_open($cmd,$desc,$pipes); if (!is_resource($proc)) { die("Failed to open process for command $cmd"); } $service_ready_marker = 'The service is listening'; $got_service_ready_marker = false; // Wait until service is ready for (;;) { $output_line = stream_get_line($pipes[1],PHP_INT_MAX,PHP_EOL); echo "Read line: $output_linen"; if ($output_line === false) { break; } if ($output_line == $service_ready_marker) { $got_service_ready_marker = true; break; } if ($error_line = stream_get_line($pipes[2],PHP_EOL)) { $startup_errors []= $error_line; } } if (!empty($startup_errors)) { fprintf(STDERR,"Startup Errors: <<<n%sn>>>n",implode(PHP_EOL,$startup_errors)); } if ($got_service_ready_marker) { echo "Got service ready markern"; $pid = pcntl_fork(); if ($pid == -1) { fprintf(STDERR,"failed to fork a processn"); fclose($pipes[1]); fclose($pipes[2]); proc_close($proc); } elseif ($pid) { // parent process // capture the output from the service $output = stream_get_contents($pipes[1]); $errors = stream_get_contents($pipes[2]); fclose($pipes[1]); fclose($pipes[2]); proc_close($proc); // Use the captured output if ($output) { file_put_contents('/tmp/service.output',$output); } if ($errors) { file_put_contents('/tmp/service.errors',$errors); } echo "Parent: waiting for child processes to finish...n"; pcntl_wait($status); echo "Parent: donen"; } else { // child process // Cleanup fclose($pipes[1]); fclose($pipes[2]); proc_close($proc); // Run unit tests echo "Child: running unit tests...n"; usleep(5e6); echo "Child: donen"; } } 样本输出 Read line: Step 1 Read line: Step 2 Read line: Step 3 Read line: Step 4 Read line: The service is listening Startup Errors: <<< Step Error 1 Step Error 2 Step Error 3 Step Error 4 >>> Got service ready marker Child: running unit tests... Parent: waiting for child processes to finish... Child: done Parent: done (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- php – 如何在Zend Framework中进行preDispatch转发?
- php – 上传多个图像并将其路径存储在数据库中
- 【BZOJ2729】【HNOI2012】排队 组合数 数论 Python高精度
- php – 在Drupal 7模板中获取自定义用户字段的值?
- php – 使用PDO :: FETCH_CLASS与魔术方法
- php+ajax发起流程和审核流程(以请假为例)
- php – Symfony 2.4 app.session.flashbag.all()返回空值
- PDO的安全处理与事物处理方法
- php – 在Codeception API测试中没有完成授权标头
- php – google analytics api查询一个特定的url