123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- <?php
- namespace KIF\Cli;
- use KIF\Verify;
- use Exception;
- use KIF\Core\Config;
- /**
- * 这是一个辅助性的东西,当你希望某个操作只运行一个进程的时候(例如生成缓存,既然生成缓存,几十个同时跑,我觉得还不如不要呢)
- * 还有像优享团结团后,发成功通知的短信,发了一次还发?sb了呢!
- *
- * @author gaoxiaogang@gmail.com
- *
- */
- class SingleProcess {
- /**
- * 唯一标识
- * @var string
- */
- private $pid;
- /**
- * 最大生存时间 单位:秒
- * @var int
- */
- private $timeout;
- /**
- * 是否检查操作系统进程
- * 该值为true时,将检查操作系统中的进程是否存在。如果不存在,返回已超时。
- * 只用于(unix/linux)
- * @var boolean
- */
- private $checkSystemProcess;
- public function __construct($pid, $timeout = 600, $checkSystemProcess = false) {
- if (!self::isValidPid($pid)) {
- throw new Exception('invalid $pid');
- }
- if (!Verify::int($timeout) || $timeout < 1) {
- throw new Exception('invalid $lifetime');
- }
- if (!is_bool($checkSystemProcess)) {
- throw new Exception('invalid $checkSystemProcess');
- }
- $this->pid = $pid;
- $this->timeout = (int) $timeout;
- $this->checkSystemProcess = $checkSystemProcess;
- }
- /**
- * 1、检测一个进程是否正在运行,如果返回true 那么就是正在运行,如果false 表示已经结束,你可以放心使用!
- * 2、当进程已经超时,也会返回false
- * 3、如果指定$this->checkSystemProcess为true,将检查操作系统中的进程是否存在。如果不存在,返回false。
- *
- * @return boolean
- */
- public function isRun() {
- $pf = $this->getPidPath();
- # 不存在
- if (!file_exists( $pf )) {
- return false;
- }
- # 超时了
- if ($this->isTimeout()) {
- $this->kill();
- return false;
- }
- # 系统进程不存在了,就认为前一个进程已经结束了。
- if ($this->checkSystemProcess) {
- $spid = $this->getSystemPid();
- if (!self::existSystemProcess($spid)) {
- return false;
- }
- }
- return true;
- }
- /**
- * 开始运行一个进程(声明:这只是一个虚拟的辅助操作,不要乱想)
- *
- * @return Boolean
- */
- public function run() {
- file_put_contents($this->getPidPath(), getmypid());
- return true;
- }
- /**
- * 激活
- * 如果new SignleProcess 时指定的timeout是600秒,当这个时间到达时,另一个进程就会将当前进程杀死。
- * 而active方法的作用,就是重新计算超时时间。
- * @param $activeFrequency 激活频率 300秒,即五分钟激活一次
- * @return boolean
- */
- public function active($activeFrequency = 300) {
- static $time_prev = null;
- if (is_null($time_prev)) {
- $time_prev = time();
- }
- $time_now = time();
- # 达到激活频率,声明脚本还活着
- if ($time_now - $time_prev >= $activeFrequency) {
- $time_prev = $time_now;//更新上次激活时间
- $this->run();
- return true;
- }
- return false;
- }
- /**
- * 进程结束
- *
- * @return Boolean
- */
- public function complete() {
- @unlink($this->getPidPath());
- return true;
- }
- /**
- * 终止一个进程
- *
- * @return Boolean
- */
- public function kill() {
- $pf = $this->getPidPath();
- if (!file_exists($pf)) {
- return true;
- }
- if ($this->checkSystemProcess) {
- $spid = $this->getSystemPid();
- if ($spid) {
- exec("kill -9 {$spid}");
- }
- }
- @unlink($pf);
- sleep(1);
- return true;
- }
- /**
- * 清除所有进程记录,不管有没结束
- *
- * @param boolean $checkSystemProcess 是否检查操作系统进程
- * @return Boolean
- */
- static public function cleanup($checkSystemProcess = false) {
- $path = self::getPath().'*';
- foreach (glob($path) as $filename) {
- if ($checkSystemProcess) {
- $spid = file_get_contents($filename);
- if (self::existSystemProcess($spid)) {
- exec("kill -9 {$spid}");//同时杀死该pid对应的操作系统进程
- }
- }
- @unlink($filename);
- }
- sleep(10);//休眠10秒
- return true;
- }
- /**
- * 取得缓存路径,如果不存在,自动创建
- *
- * @return String
- */
- static private function getPath() {
- # TODO 配置文件中 Log_Path
- $logPath = Config::getInstance ()->get ( 'Log_Path' );
-
- if(empty($logPath)){
- throw new Exception('Config Log_Path is empty');
- }
-
- $path = $logPath . DS . 'sspfiles' . DS;
- if (!file_exists($path)) {
- if (!mkdir($path, 0777, true)) {
- return false;
- }
- }
- return $path;
- }
- /**
- * 是否超时
- * @return Boolean
- */
- private function isTimeout() {
- if ((time() - filemtime($this->getPidPath())) > $this->timeout) {
- return true;
- }
- return false;
- }
- /**
- * 获取存放pid的全路径,包括pid文件名
- * @return string
- */
- private function getPidPath() {
- return self::getPath() . md5($this->pid);
- }
- /**
- * 获取系统进程pid
- * @return int | false
- */
- private function getSystemPid() {
- $spid = @file_get_contents($this->getPidPath());
- if ($spid) {
- return $spid;
- }
- return false;
- }
- /**
- * 是否存在操作系统进程
- *
- * @param int $spid 操作系统进程id
- * @return Boolean
- */
- static private function existSystemProcess($spid) {
- if (!Verify::int($spid) || $spid < 1) {
- return false;
- }
- $cmd = 'ps -eo pid | egrep ^\ *'.$spid.'$';
- $out = shell_exec($cmd);
- return empty($out) ? false : true;
- }
- /**
- * 是否有效的pid
- * @param string $pid
- * @return boolean
- */
- static private function isValidPid($pid) {
- if (!is_string($pid) || empty($pid)) {
- return false;
- }
- return true;
- }
- }
|