arara/process

为Unix-like系统上的进程工作提供更好的API

1.10.0 2015-06-03 19:54 UTC

README

Build Status Code Quality Code Coverage Latest Version Total Downloads License

此库通过PHP为Unix-like系统上的进程工作提供更好的API。

安装

该包可在Packagist上找到。您可以使用Composer进行安装。

composer require arara/process

依赖关系

Arara\Process的版本1.6.0或更低在PHP 5.3上工作。

用法

除了本文档外,examples/ 目录中还有许多用法示例,这些示例可能被用作参考。

本文档中的所有示例都假设您在文件开头有以下声明

declare(ticks=1);

如果没有这个声明,无法保证PHP会处理信号;这对PCNTL的正常工作非常重要。自PHP 4.3.0版本以来就要求这样做,因此这不是库的要求,而是PHP语言本身的要求。

如果您想了解更多关于ticks的信息,我们建议您阅读https://php.ac.cn/declare#control-structures.declare.ticks

动作接口

可以使用Arara\Process\Action\Action接口封装Fork。实现此接口的所有类必须实现两个方法

  • execute(..):可能包含在后台执行的操作
  • trigger(...):可能包含针对特定事件的特定操作

使用此接口,您可以创建自己的操作并在后台运行它们。

事件

如所写,Arara\Process\Action\Action::trigger(..)方法将特定操作与事件关联。这些事件可以是

  • Action::EVENT_INIT:在操作初始化时触发
    • 当操作附加到子对象时
  • Action::EVENT_FORK:在操作Fork时触发
    • 在操作Fork后,在进程中触发
  • Action::EVENT_START:在执行execute()方法之前触发
  • Action::EVENT_SUCCESS:在操作成功完成后触发,即
    • 当操作没有遇到PHP错误时
    • 当操作没有抛出异常时
    • 当操作没有返回任何值时
    • 当操作返回Action::EVENT_SUCCESS值时
  • Action::EVENT_ERROR:在操作遇到错误时触发,即
    • 当操作遇到PHP错误时
    • 当操作返回Action:EVENT_ERROR值时
  • Action::EVENT_FAILURE:在操作完成并失败后触发,即
    • 当操作抛出异常时
    • 当操作返回Action::EVENT_FAILURE值时
  • Action::EVENT_TIMEOUT:在操作遇到超时时触发
  • Action::EVENT_FINISH :在execute()方法执行后触发。

回调操作

为了在不创建特定类执行后台操作的情况下执行Fork,有一个通用的实现允许在后台运行回调;唯一需要做的事情是将回调传递给此类的构造函数。

use Arara\Process\Action\Callback;

$callback = new Callback(function () {
    echo "This will be executed in the background!" . PHP_EOL;
});

回调动作提供了一种将回调绑定到特定事件触发的方法

$callback->bind(Callback::EVENT_SUCCESS, function () {
    echo "This will be executed if the action callback was successful!" . PHP_EOL;
});

此外,还可以将回调绑定到多个事件

$callback->bind(Callback::EVENT_ERROR | Callback::EVENT_FAILURE, function () {
    echo "It is going to be executed if the action fails or get an error" . PHP_EOL;
});

命令动作

如果您只想运行Linux命令,因此存在命令动作。

$command = new Command('whoami');

使用命令动作,您可以将参数定义为第二个参数

$command = new Command('cp', array('/path/to/source', '/path/to/destination'));

如果您希望通过键 => 值数组定义参数

$command = new Command(
    'find',
    array(
        '/path/to/dir',
        '-name' => '*',
        '-type' => 'f',
    )
);

命令动作基于回调动作,因此您也可以绑定事件触发器。

守护进程动作

您可以使用Arara\Process\Action\Daemon类创建守护进程

$daemon = new Daemon(
    function (Control $control, Context $context, Daemon $daemon) {
        while (! $daemon->isDying()) {
            // Do whatever you want =)
        }
    }
);

此动作将

  1. 使进程会话与父进程分离
  2. 更新进程umask
  3. 更新进程工作目录
  4. 定义进程GID(如果已定义)
  5. 定义进程UID(如果已定义)
  6. 重新创建标准文件描述符(STDIN,STDOUT和STDERR)
  7. 创建Pidfile
  8. 运行定义的负载回调

守护进程动作基于回调动作,因此您也可以绑定事件触发器。

守护进程选项

守护进程动作类有一些选项,允许您更改某些行为

  • name:用于pidfile的名称(默认arara
  • lock_dir:pidfile的锁目录(默认/var/run)
  • work_dir:工作目录(默认/
  • umask:默认umask值(默认0
  • user_id:当定义时更改守护进程UID(默认NULL
  • group_id:当定义时更改守护进程GID(默认NULL
  • stdin:用作STDIN的文件(默认/dev/null
  • stdout:用作STDOUT的文件(默认/dev/null
  • stderr:用作STDERR的文件(默认/dev/null

您可以通过在类构造函数中定义来更改默认的守护进程选项

$daemon = new Daemon(
    $callback,
    array(
        'name' => 'mydaemonname',
        'lock_dir' => __DIR__,
    )
);

在对象创建之后,您还可以更改所有选项

$daemon->setOptions(
    array(
        'stdout' => '/tmp/daemon.stdout',
        'stderr' => '/tmp/daemon.stderr',
    )
);

此外,您还可以更改单个选项

$daemon->setOption('work_dir', __DIR__);

在后台启动进程

Arara\Process\Child允许您在后台执行任何动作。

$child = new Child(
    new Daemon(function () {
        // What my daemon does...
    }),
    new Control()
);
$child->start(); // Runs the callback in the background

上面的例子在后台运行守护进程动作,但也可以使用任何实现Arara\Process\Action\Action接口的类,如回调动作。

检查进程是否在运行

检查进程是否在运行是一个非常常见的操作;要使用此库执行此操作,您可能需要调用

$child->isRunning(); // Returns TRUE if it is running or FALSE if it is not

此方法不仅检查对象的状态,而且还检查进程是否已经在系统上运行。

终止进程

如果进程已经启动,这将告诉进程终止,但不会强制它。

$child->terminate(); // Sends a SIGTERM to the process

杀死进程

如果它已经启动,这将强制进程立即终止。

$child->kill(); // Sends a SIGKILL to the process

等待进程

如果您想等待进程完成,而不是仅在后台启动进程,您可以调用

$child->wait();

下一行代码将在进程完成后执行。

获取进程状态

在等待进程完成后,可以获取进程的状态。类Arara\Process\Child有一个名为getStatus()的方法,允许您检查进程的状态。

$child->getStatus(); // Returns an Arara\Process\Control\Status instance

内部,这调用wait()方法,以便等待进程完成 - 然后获取其状态。

获取进程的退出码

$child->getStatus()->getExitStatus();

获取导致进程停止的信号

$child->getStatus()->getStopSignal();

获取导致进程终止的信号

$child->getStatus()->getTerminateSignal();

检查状态码是否表示正常退出

$child->getStatus()->isExited();

检查状态码是否表示由于信号而终止

$child->getStatus()->isSignaled();

检查进程是否已停止

$child->getStatus()->isStopped();

检查进程是否成功完成

$child->getStatus()->isSuccessful();

孵化

由于您正在处理fork,因此您还可以使用spawn。类Arara\Process\Pool提供了一个简单的方法来处理它。

该类动态处理进程队列,您需要做的只是在其构造函数中提供您想要的子进程数量限制,然后附加子进程。

$maxConcurrentChildren = 2;
$pool = new Pool($maxConcurrentChildren);
$pool->start();

$pool->attach(new Child(/* ... */));
$pool->attach(new Child(/* ... */));
$pool->attach(new Child(/* ... */));
$pool->attach(new Child(/* ... */));
// ...

它拥有的子进程数量无关紧要;它只会同时运行2个进程;当其中一个进程完成时,它将从队列中移除,并打开一个新槽。

Arara\Process\Pool 类包含大部分 Arara\Process\Child 类的方法

  • isRunning()
  • kill()
  • start()
  • terminate()
  • wait()

所有方法的行为都类似。

控制类

您也可以不使用池、子进程或操作类来处理进程。

我们提供了一个简单的API来与 pcntl_*posix_* 函数一起工作。您可以通过阅读 Arara\Process\Control 及其依赖项的代码来了解更多信息,但这里有一个示例

$control = new Control();
$pid = $control->fork();// Throws RuntimeException when pcntl_fork() returns -1
if ($pid > 0) {
    echo 'Waiting on child...' . PHP_EOL;
    $control->waitProcessId($pid);
    echo 'Child finished' . PHP_EOL;
    $control->quit();
}

echo 'Child process has PID ' . $control->info()->getId() . PHP_EOL;
echo 'Child process has parent PID ' . $control->info()->getParentId() . PHP_EOL;

$control->flush(2.5); // Will try to flush current process memory and sleep by 2 and a half seconds
$control->signal()->send('kill'); // Will send SIGKILL to the current process (the child)

进程ID文件类

如果您正在处理后台任务,您可能想要创建一个锁来避免人们重复运行您的脚本。为此,有 Arara\Process\Pidfile 类。

$control = new Control();
$applicationName = 'my_app';
$pidfile = new Pidfile($control, $applicationName);
$pidfile->initialize();

// Whatever you need here...

$pidfile->finalize();

当有人第二次运行它时,将抛出异常。我们建议您将此代码放入 try..catch 语句中。